Leaked source code of windows server 2003
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.
 
 
 
 
 
 

624 lines
21 KiB

#include <windows.h>
#include <regstr.h>
#include <shellapi.h>
#include "cdinst.h"
#include "resource.h"
// global variables
HINSTANCE g_hInst;
CHAR g_szTitle[128];
CHAR g_szSrcDir[MAX_PATH], g_szDstDir[MAX_PATH];
int _stdcall ModuleEntry(void)
{
int i;
STARTUPINFO si;
LPSTR pszCmdLine = GetCommandLine();
if ( *pszCmdLine == '\"' ) {
/*
* Scan, and skip over, subsequent characters until
* another double-quote or a null is encountered.
*/
while ( *++pszCmdLine && (*pszCmdLine != '\"') )
;
/*
* If we stopped on a double-quote (usual case), skip
* over it.
*/
if ( *pszCmdLine == '\"' )
pszCmdLine++;
}
else {
while (*pszCmdLine > ' ')
pszCmdLine++;
}
/*
* Skip past any white space preceeding the second token.
*/
while (*pszCmdLine && (*pszCmdLine <= ' ')) {
pszCmdLine++;
}
si.dwFlags = 0;
GetStartupInfoA(&si);
i = WinMain(GetModuleHandle(NULL), NULL, pszCmdLine,
si.dwFlags & STARTF_USESHOWWINDOW ? si.wShowWindow : SW_SHOWDEFAULT);
ExitProcess(i);
return i; // We never comes here.
}
INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pszCmdLine, INT iCmdShow)
{
BOOL bIniCopiedToTemp = FALSE;
CHAR szIniFile[MAX_PATH], szSrcDir[MAX_PATH], szDstDir[MAX_PATH];
LPSTR pszSection, pszPtr, pszLine, pszFile, pszSrcSubDir, pszDstSubDir;
DWORD dwLen, dwSpaceReq, dwSpaceFree;
g_hInst = hInstance;
LoadString(g_hInst, IDS_TITLE, g_szTitle, sizeof(g_szTitle));
ParseCmdLine(pszCmdLine);
if (*g_szSrcDir == '\0')
{
if (GetModuleFileName(g_hInst, g_szSrcDir, sizeof(g_szSrcDir)))
if ((pszPtr = ANSIStrRChr(g_szSrcDir, '\\')) != NULL)
*pszPtr = '\0';
if (*g_szSrcDir == '\0')
{
ErrorMsg(IDS_SRCDIR_NOT_FOUND);
return -1;
}
}
if (*g_szDstDir == '\0')
{
HKEY hk;
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_APPPATHS "\\ieak6wiz.exe", 0, KEY_READ, &hk) == ERROR_SUCCESS)
{
dwLen = sizeof(g_szDstDir);
RegQueryValueEx(hk, "Path", NULL, NULL, (LPBYTE) g_szDstDir, &dwLen);
RegCloseKey(hk);
}
if (*g_szDstDir == '\0')
{
ErrorMsg(IDS_DESTDIR_NOT_FOUND);
return -1;
}
}
// look for cdinst.ini in the dir where the parent module (ieak6cd.exe) is running from
*szIniFile = '\0';
lstrcpy(szIniFile, g_szSrcDir);
AddPath(szIniFile, "cdinst.ini");
if (!FileExists(szIniFile))
{
// not found where ieak6cd.exe is running from; so look for it in the dir where the current
// module (cdinst.exe) is running from
*szIniFile = '\0';
if (GetModuleFileName(g_hInst, szIniFile, sizeof(szIniFile)))
{
if ((pszPtr = ANSIStrRChr(szIniFile, '\\')) != NULL)
*pszPtr = '\0';
AddPath(szIniFile, "cdinst.ini");
}
if (!FileExists(szIniFile))
{
*szIniFile = '\0';
GetModuleFileName(g_hInst, szIniFile, sizeof(szIniFile));
ErrorMsg(IDS_INI_NOT_FOUND, g_szSrcDir, szIniFile);
return -1;
}
}
// copy cdinst.ini to the temp dir -- need to do this because on Win95, if cdinst.ini
// is at the same location as ieak6cd.exe on a read-only media (like CD), then
// GetPrivateProfileSection() calls would fail.
// NOTE: szSrcDir and szDstDir are used as temp variables below
if (GetTempPath(sizeof(szSrcDir), szSrcDir))
if (GetTempFileName(szSrcDir, "cdinst", 0, szDstDir))
if (CopyFile(szIniFile, szDstDir, FALSE))
{
bIniCopiedToTemp = TRUE;
lstrcpy(szIniFile, szDstDir);
SetFileAttributes(szIniFile, FILE_ATTRIBUTE_NORMAL);
}
// NOTE: If the destination dir is a UNC path, GetFreeDiskSpace() won't return the right value on Win95 Gold.
// So we turn off disk space checking if installing to a UNC path.
while (!EnoughDiskSpace(g_szSrcDir, g_szDstDir, szIniFile, &dwSpaceReq, &dwSpaceFree))
{
if (ErrorMsg(IDS_NOT_ENOUGH_DISK_SPACE, dwSpaceReq, dwSpaceFree) == IDNO)
return -1;
}
// copy files that are specified in the [copy] section
// format of a line in the [copy] section is (all the fields should be on one line):
// <file (can contain wildcards)>,
// <src sub dir (can be a relative path) - optional>,
// <dest sub dir (can be a relative path) - optional>
if (ReadSectionFromInf("Copy", &pszSection, &dwLen, szIniFile))
{
for (pszLine = pszSection; dwLen = lstrlen(pszLine); pszLine += dwLen + 1)
{
ParseIniLine(pszLine, &pszFile, &pszSrcSubDir, &pszDstSubDir);
GetDirPath(g_szSrcDir, pszSrcSubDir, szSrcDir, sizeof(szSrcDir), szIniFile);
GetDirPath(g_szDstDir, pszDstSubDir, szDstDir, sizeof(szDstDir), szIniFile);
CopyFiles(szSrcDir, pszFile, szDstDir, FALSE);
}
}
if (pszSection != NULL)
LocalFree(pszSection);
// delete files that are specified in the [exclude] section from the destination dir
// format of a line in the [exclude] section is (all the fields should be on one line):
// <file (can contain wildcards)>,
// <dest sub dir (can be a relative path) - optional>
if (ReadSectionFromInf("Exclude", &pszSection, &dwLen, szIniFile))
{
for (pszLine = pszSection; dwLen = lstrlen(pszLine); pszLine += dwLen + 1)
{
ParseIniLine(pszLine, &pszFile, NULL, &pszDstSubDir);
GetDirPath(g_szDstDir, pszDstSubDir, szDstDir, sizeof(szDstDir), szIniFile);
DelFiles(pszFile, szDstDir);
}
}
if (pszSection != NULL)
LocalFree(pszSection);
// extract all the files from cabs that are specified in the [extract] section
// format of a line in the [extract] section is (all the fields should be on one line):
// <cab file (can contain wildcards)>,
// <src sub dir (can be a relative path) - optional>,
// <dest sub dir (can be a relative path) - optional>
if (ReadSectionFromInf("Extract", &pszSection, &dwLen, szIniFile))
{
HINSTANCE hAdvpack;
if ((hAdvpack = LoadLibrary("advpack.dll")) != NULL)
{
EXTRACTFILES pfnExtractFiles;
if ((pfnExtractFiles = (EXTRACTFILES) GetProcAddress(hAdvpack, "ExtractFiles")) != NULL)
{
for (pszLine = pszSection; dwLen = lstrlen(pszLine); pszLine += dwLen + 1)
{
ParseIniLine(pszLine, &pszFile, &pszSrcSubDir, &pszDstSubDir);
GetDirPath(g_szSrcDir, pszSrcSubDir, szSrcDir, sizeof(szSrcDir), szIniFile);
GetDirPath(g_szDstDir, pszDstSubDir, szDstDir, sizeof(szDstDir), szIniFile);
ExtractFiles(szSrcDir, pszFile, szDstDir, pfnExtractFiles);
}
}
FreeLibrary(hAdvpack);
}
}
if (pszSection != NULL)
LocalFree(pszSection);
// move files that are specified in the [move] section from a subdir to another subdir under the destination dir
// format of a line in the [move] section is (all the fields should be on one line):
// <file (can contain wildcards)>,
// <from sub dir under the dest dir (can be a relative path) - optional>,
// <to sub dir under the dest dir (can be a relative path) - optional>
if (ReadSectionFromInf("Move", &pszSection, &dwLen, szIniFile))
{
for (pszLine = pszSection; dwLen = lstrlen(pszLine); pszLine += dwLen + 1)
{
ParseIniLine(pszLine, &pszFile, &pszSrcSubDir, &pszDstSubDir);
GetDirPath(g_szDstDir, pszSrcSubDir, szSrcDir, sizeof(szSrcDir), szIniFile);
GetDirPath(g_szDstDir, pszDstSubDir, szDstDir, sizeof(szDstDir), szIniFile);
MoveFiles(szSrcDir, pszFile, szDstDir);
}
}
if (pszSection != NULL)
LocalFree(pszSection);
if (bIniCopiedToTemp)
DeleteFile(szIniFile);
return 0;
}
BOOL EnoughDiskSpace(LPCSTR pcszSrcRootDir, LPCSTR pcszDstRootDir, LPCSTR pcszIniFile, LPDWORD pdwSpaceReq, LPDWORD pdwSpaceFree)
// check if there is enough free disk space to copy all the files
{
DWORD dwSpaceReq = 0, dwSpaceFree;
CHAR szSrcDir[MAX_PATH], szDstDir[MAX_PATH];
LPSTR pszSection, pszLine, pszFile, pszSrcSubDir, pszDstSubDir;
DWORD dwLen, dwFlags;
if (!GetFreeDiskSpace(pcszDstRootDir, &dwSpaceFree, &dwFlags))
{
// if we can't get FreeDiskSpace info, then turn off disk space checking
return TRUE;
}
// total space required =
// size of all the files to be copied +
// 2 * size of all the files to be extracted
if (ReadSectionFromInf("Copy", &pszSection, &dwLen, pcszIniFile))
{
for (pszLine = pszSection; dwLen = lstrlen(pszLine); pszLine += dwLen + 1)
{
ParseIniLine(pszLine, &pszFile, &pszSrcSubDir, &pszDstSubDir);
GetDirPath(pcszSrcRootDir, pszSrcSubDir, szSrcDir, sizeof(szSrcDir), pcszIniFile);
GetDirPath(pcszDstRootDir, pszDstSubDir, szDstDir, sizeof(szDstDir), pcszIniFile);
dwSpaceReq += FindSpaceRequired(szSrcDir, pszFile, szDstDir);
}
}
if (pszSection != NULL)
LocalFree(pszSection);
if (ReadSectionFromInf("Extract", &pszSection, &dwLen, pcszIniFile))
{
for (pszLine = pszSection; dwLen = lstrlen(pszLine); pszLine += dwLen + 1)
{
ParseIniLine(pszLine, &pszFile, &pszSrcSubDir, NULL);
GetDirPath(pcszSrcRootDir, pszSrcSubDir, szSrcDir, sizeof(szSrcDir), pcszIniFile);
dwSpaceReq += 2 * FindSpaceRequired(szSrcDir, pszFile, NULL);
}
}
if (pszSection != NULL)
LocalFree(pszSection);
dwSpaceReq += 1024; // 1MB buffer to account for random stuff
if (dwFlags & FS_VOL_IS_COMPRESSED)
{
// if the destination volume is compressed, the free space returned is only
// a guesstimate; for example, if it's a DoubleSpace volume, the system thinks
// that it can compress by 50% and so it reports the free space as (actual free space * 2)
// it's better to be safe when dealing with compressed volumes; so bump up the space
// requirement by a factor 2
dwSpaceReq <<= 1; // multiply by 2
}
if (pdwSpaceReq != NULL)
*pdwSpaceReq = dwSpaceReq;
if (pdwSpaceFree != NULL)
*pdwSpaceFree = dwSpaceFree;
return dwSpaceFree > dwSpaceReq;
}
BOOL GetFreeDiskSpace(LPCSTR pcszDir, LPDWORD pdwFreeSpace, LPDWORD pdwFlags)
// Return the free disk space (in KBytes) in *pdwFreeSpace
{
BOOL bRet = FALSE;
DWORD dwFreeSpace = 0;
DWORD nSectorsPerCluster, nBytesPerSector, nFreeClusters, nTotalClusters;
CHAR szDrive[8];
if (pcszDir == NULL || *pcszDir == '\0' || *(pcszDir + 1) != ':')
return FALSE;
if (pdwFreeSpace == NULL)
return FALSE;
lstrcpyn(szDrive, pcszDir, 3);
AddPath(szDrive, NULL);
if (GetDiskFreeSpace(szDrive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters))
{
// convert size to KBytes; assumption here is that the free space doesn't exceed 4096 gigs
if ((*pdwFreeSpace = MulDiv(nFreeClusters, nSectorsPerCluster * nBytesPerSector, 1024)) != (DWORD) -1)
{
bRet = TRUE;
if (pdwFlags != NULL)
{
*pdwFlags = 0;
GetVolumeInformation(szDrive, NULL, 0, NULL, NULL, pdwFlags, NULL, 0);
}
}
}
return bRet;
}
DWORD FindSpaceRequired(LPCSTR pcszSrcDir, LPCSTR pcszFile, LPCSTR pcszDstDir)
// Return the difference in size (in KBytes) of pcszFile (can contain wildcards)
// under pcszSrcDir and pcszDstDir (if specified)
{
DWORD dwSizeReq = 0;
CHAR szSrcFile[MAX_PATH], szDstFile[MAX_PATH];
LPSTR pszSrcPtr, pszDstPtr;
WIN32_FIND_DATA fileData;
HANDLE hFindFile;
lstrcpy(szSrcFile, pcszSrcDir);
AddPath(szSrcFile, NULL);
pszSrcPtr = szSrcFile + lstrlen(szSrcFile);
if (pcszDstDir != NULL)
{
lstrcpy(szDstFile, pcszDstDir);
AddPath(szDstFile, NULL);
pszDstPtr = szDstFile + lstrlen(szDstFile);
}
lstrcpy(pszSrcPtr, pcszFile);
if ((hFindFile = FindFirstFile(szSrcFile, &fileData)) != INVALID_HANDLE_VALUE)
{
do
{
if (!(fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
{
DWORD dwSrcSize, dwDstSize;
// assumption here is that the size of the file doesn't exceed 4 gigs
dwSrcSize = fileData.nFileSizeLow;
dwDstSize = 0;
if (pcszDstDir != NULL)
{
lstrcpy(pszDstPtr, fileData.cFileName);
dwDstSize = FileSize(szDstFile);
}
if (dwSrcSize >= dwDstSize)
{
// divide the difference by 1024 (we are interested in KBytes)
dwSizeReq += ((dwSrcSize - dwDstSize) >> 10);
if (dwSrcSize > dwDstSize)
dwSizeReq++; // increment by 1 to promote any fraction to a whole number
}
}
} while (FindNextFile(hFindFile, &fileData));
FindClose(hFindFile);
}
return dwSizeReq;
}
VOID ParseIniLine(LPSTR pszLine, LPSTR *ppszFile, LPSTR *ppszSrcDir, LPSTR *ppszDstDir)
{
if (ppszFile != NULL)
*ppszFile = Trim(GetNextField(&pszLine, ",", REMOVE_QUOTES));
if (ppszSrcDir != NULL)
*ppszSrcDir = Trim(GetNextField(&pszLine, ",", REMOVE_QUOTES));
if (ppszDstDir != NULL)
*ppszDstDir = Trim(GetNextField(&pszLine, ",", REMOVE_QUOTES));
}
LPSTR GetDirPath(LPCSTR pcszRootDir, LPCSTR pcszSubDir, CHAR szDirPath[], DWORD cchBuffer, LPCSTR pcszIniFile)
{
*szDirPath = '\0';
if (pcszRootDir == NULL)
return NULL;
lstrcpyn(szDirPath, pcszRootDir, cchBuffer);
if (pcszSubDir != NULL && *pcszSubDir)
{
CHAR szTemp[MAX_PATH];
// if there are any placeholders in pcszSubDir (%en%, etc), ReplacePlaceholders will replace
// them with the actual strings
if (ReplacePlaceholders(pcszSubDir, pcszIniFile, szTemp, sizeof(szTemp)))
{
if ((DWORD) lstrlen(szDirPath) + 1 < cchBuffer) // there is room for '\\' which AddPath
// might append to szDirPath (see below)
{
INT iLen;
AddPath(szDirPath, NULL); // we have enough room in szDirPath for '\\'
if (cchBuffer > (DWORD) (iLen = lstrlen(szDirPath)))
lstrcpyn(szDirPath + iLen, szTemp, cchBuffer - iLen);
}
}
}
return szDirPath;
}
DWORD ReplacePlaceholders(LPCSTR pszSrc, LPCSTR pszIns, LPSTR pszBuffer, DWORD cchBuffer)
{
LPCSTR pszAux;
CHAR szResult[MAX_PATH];
UINT nDestPos, nLeftPos;
nDestPos = 0;
nLeftPos = (UINT) -1;
for (pszAux = pszSrc; *pszAux; pszAux = CharNext(pszAux))
{
if (*pszAux != '%')
{
szResult[nDestPos++] = *pszAux;
if (IsDBCSLeadByte(*pszAux))
szResult[nDestPos++] = *(pszAux + 1); // copy the trail byte as well
}
else if (*(pszAux + 1) == '%') // "%%" is just '%' in the string
{
if (nLeftPos != (UINT) -1)
// REVIEW: (andrewgu) "%%" are not allowed inside tokens. this also means that
// tokens can't be like %foo%%bar%, where the intention is for foo and bar to
// be tokens.
return 0;
szResult[nDestPos++] = *pszAux++;
}
else
{
UINT nRightPos;
nRightPos = (UINT) (pszAux - pszSrc); // initialized, but not necessarily used as such
if (nLeftPos == (UINT) -1)
nLeftPos = nRightPos;
else
{
CHAR szAux1[MAX_PATH], szAux2[MAX_PATH];
DWORD dwLen;
UINT nTokenLen;
// "%%" is invalid here
nTokenLen = nRightPos - nLeftPos - 1;
lstrcpyn(szAux1, pszSrc + nLeftPos + 1, nTokenLen + 1);
if ((dwLen = GetPrivateProfileString("Strings", szAux1, "", szAux2, sizeof(szAux2), pszIns)))
{
lstrcpy(&szResult[nDestPos - nTokenLen], szAux2);
nDestPos += dwLen - nTokenLen;
}
nLeftPos = (UINT) -1;
}
}
}
if (nLeftPos != (UINT) -1) // mismatched '%'
return 0;
if (cchBuffer <= nDestPos) // insufficient buffer size
return 0;
szResult[nDestPos] = '\0'; // make sure zero terminated
lstrcpy(pszBuffer, szResult);
return nDestPos;
}
VOID SetAttribsToNormal(LPCSTR pcszFile, LPCSTR pcszDir)
// Set the attribs of pcszFile (can contain wildcards) under pcszDir to NORMAL
{
CHAR szFile[MAX_PATH];
LPSTR pszPtr;
WIN32_FIND_DATA fileData;
HANDLE hFindFile;
lstrcpy(szFile, pcszDir);
AddPath(szFile, NULL);
pszPtr = szFile + lstrlen(szFile);
lstrcpy(pszPtr, pcszFile);
if ((hFindFile = FindFirstFile(szFile, &fileData)) != INVALID_HANDLE_VALUE)
{
do
{
if (!(fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
{
lstrcpy(pszPtr, fileData.cFileName);
SetFileAttributes(szFile, FILE_ATTRIBUTE_NORMAL);
}
} while (FindNextFile(hFindFile, &fileData));
FindClose(hFindFile);
}
}
VOID CopyFiles(LPCSTR pcszSrcDir, LPCSTR pcszFile, LPCSTR pcszDstDir, BOOL fQuiet)
{
SHFILEOPSTRUCT shfStruc;
CHAR szSrcFiles[MAX_PATH + 1];
if (!PathExists(pcszDstDir))
PathCreatePath(pcszDstDir);
else
{
// set the attribs of files under pcszDstDir to NORMAL so that on a reinstall,
// SHFileOperation doesn't choke on read-only files
SetAttribsToNormal(pcszFile, pcszDstDir);
}
ZeroMemory(szSrcFiles, sizeof(szSrcFiles));
lstrcpy(szSrcFiles, pcszSrcDir);
AddPath(szSrcFiles, pcszFile);
ZeroMemory(&shfStruc, sizeof(shfStruc));
shfStruc.hwnd = NULL;
shfStruc.wFunc = FO_COPY;
shfStruc.pFrom = szSrcFiles;
shfStruc.pTo = pcszDstDir;
shfStruc.fFlags = FOF_FILESONLY | FOF_NOCONFIRMATION | FOF_NOCONFIRMMKDIR;
if (fQuiet)
shfStruc.fFlags |= FOF_SILENT;
SHFileOperation(&shfStruc);
}
VOID DelFiles(LPCSTR pcszFile, LPCSTR pcszDstDir)
{
SHFILEOPSTRUCT shfStruc;
CHAR szDstFiles[MAX_PATH + 1];
// set the attribs of files under pcszDstDir to NORMAL so that
// SHFileOperation doesn't choke on read-only files
SetAttribsToNormal(pcszFile, pcszDstDir);
ZeroMemory(szDstFiles, sizeof(szDstFiles));
lstrcpy(szDstFiles, pcszDstDir);
AddPath(szDstFiles, pcszFile);
ZeroMemory(&shfStruc, sizeof(shfStruc));
shfStruc.hwnd = NULL;
shfStruc.wFunc = FO_DELETE;
shfStruc.pFrom = szDstFiles;
shfStruc.fFlags = FOF_FILESONLY | FOF_NOCONFIRMATION | FOF_SILENT | FOF_NOERRORUI;
SHFileOperation(&shfStruc);
}
VOID ExtractFiles(LPCSTR pcszSrcDir, LPCSTR pcszFile, LPCSTR pcszDstDir, EXTRACTFILES pfnExtractFiles)
{
CHAR szSrcCab[MAX_PATH];
lstrcpy(szSrcCab, pcszSrcDir);
AddPath(szSrcCab, pcszFile);
// NOTE: ExtractFiles fails if the dest dir doesn't exist
if (!PathExists(pcszDstDir))
PathCreatePath(pcszDstDir);
else
{
// set the attribs of all the files under pcszDstDir to NORMAL so that on a reinstall,
// ExtractFiles doesn't choke on read-only files
SetAttribsToNormal("*.*", pcszDstDir);
}
pfnExtractFiles(szSrcCab, pcszDstDir, 0, NULL, NULL, 0);
}
VOID MoveFiles(LPCSTR pcszSrcDir, LPCSTR pcszFile, LPCSTR pcszDstDir)
{
// Can't use SHFileOperation to move files because on a reinstall,
// we get an error saying that the target files already exist.
// Workaround is to call CopyFiles and then DelFiles.
CopyFiles(pcszSrcDir, pcszFile, pcszDstDir, TRUE);
DelFiles(pcszFile, pcszSrcDir);
}