|
|
/*
* copy.c - Copy routine for WinDosSetup * Todd Laney * * Modification History: * * 6/03/91 Vlads Change copy process to incorporate new Install API * * 3/24/89 Toddla Wrote it * * * notes: * we now use the LZCopy stuff for compression * we now set the crit error handler ourselves so CHECKFLOPPY is * NOT defined */
#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <mmsystem.h>
#include "drivers.h"
#include "sulib.h"
//#include <ver.h>
#define MAX_COPY_ATTEMPTS 15
/*
* Maximum number of install disks we support */
#define MAX_DISKS 100
/*
* Flags for VerInstallFile */
#define FORCEABLE_FLAGS (VIF_MISMATCH + VIF_SRCOLD + VIF_DIFFLANG + VIF_DIFFTYPE + VIF_DIFFCODEPG )
/**********************************************************************
* * Local function prototypes. * **********************************************************************/
// Retrieve disk path for logical disk
BOOL GetDiskPath(LPTSTR Disk, LPTSTR szPath);
// Convert VIF_... to ERROR... return codes
UINT ConvertFlagToValue(DWORD dwFlags);
// Do the work of trying to copy a file
LONG TryCopy(LPTSTR szSrc, // Full source file path
LPTSTR szLogSrc, // Logical source name
LPTSTR szDestPath,// Destination path
FPFNCOPY fpfnCopy); // Callback routine
#ifdef CHECK_FLOPPY
BOOL NEAR IsDiskInDrive(int iDisk); #endif
// GLOBAL VARIABLES
// directory where windows will be setup to
TCHAR szSetupPath[MAX_PATH];
// directory where the root of the setup disks are!
TCHAR szDiskPath[MAX_PATH];
// Name of driver being copied (or oemsetup.inf)
TCHAR szDrv[120];
/*
* global vars used by DosCopy */ static LPTSTR lpBuf = NULL; // copy buffer
static int iBuf = 0; // usage count
static UINT nBufSize; BOOL bRetry = FALSE; BOOL bQueryExist;
extern BOOL bCopyEvenIfOlder; // From DRIVERS.C
BOOL DefCopyCallback(int msg, DWORD_PTR n, LPTSTR szFile) { return FC_IGNORE; }
/* UINT FileCopy (szSource, szDir, fpfnCopy, UINT fCopy)
* * This function will copy a group of files to a single destination * * ENTRY: * * szSourc : pointer to a SETUP.INF section * szDir : pointer to a string containing the target DIR * fpfnCopy : callback function used to notify called of copy status * fCopy : flags * * FC_SECTION - szSource is a section name * FC_LIST - szSource is a pointer to a char **foo; * FC_LISTTYPE - szSource is a pointer to a char *foo[]; * FC_FILE - szSource is a file name. * FC_QUALIFIED - szSource is a fully qualified file name. * FC_DEST_QUALIFIED - szDir is fully qualified. Don't expand this. * FC_CALLBACK_WITH_VER - call back if file exists and report version information. * * NOTES: * if szSource points to a string of the form '#name' the section * named by 'name' will be used as the source files * * the first field of each line in the secion is used as the name of the * source file. A file name has the following form: * * #:name * * # - Disk number containing file 1-9,A-Z * name - name of the file, may be a wild card expression * * Format for copy status function * * BOOL FAR PASCAL CopyStatus(int msg, int n, LPSTR szFile) * * msg: * COPY_ERROR error occured while copying file(s) * n is the DOS error number * szFile is the file that got the error * return: TRUE ok, FALSE abort copy * * COPY_STATUS Called each time a new file is copied * n is the percent done * szFile is the file being copied * return: TRUE ok, FALSE abort copy * * COPY_INSERTDISK Please tell the user to insert a disk * n is the disk needed ('1' - '9') * return: TRUE try again, FALSE abort copy * * COPY_QUERYCOPY Should this file be copied? * n line index in SETUP.INF section (0 based) * szFile is the line from section * return: TRUE copy it, FALSE dont copy * * COPY_START Sent before any files are copied * * COPY_END Sent after all files have been copied * n is dos error if copy failed * * COPY_EXISTS Sent if the FC_CALL_ON_EXIST bit was set * and the file exists at the destination * given for the filecopy. * * * EXIT: returns TRUE if successful, FALSE if failure. * */
UINT FileCopy (LPTSTR szSource, LPTSTR szDir, FPFNCOPY fpfnCopy, UINT fCopy) { int err = ERROR_SUCCESS; // Return code from this routine
TCHAR szPath[MAX_PATH]; TCHAR szLogSrc[MAX_PATH]; TCHAR szSrc[MAX_PATH];
LPTSTR pFileBegin; // First file
LPTSTR * List; // Handle lists of files
LPTSTR * ListHead;
int nDisk; // The disk we're on
int cntFiles = 0; // How many files we've got to do
if (fpfnCopy == NULL) { fpfnCopy = DefCopyCallback; }
if (!szSource || !*szSource || !szDir || !*szDir) { return ERROR_FILE_NOT_FOUND; }
/*
* fix up the drive in the destination */
if ( fCopy & FC_DEST_QUALIFIED ) { lstrcpy(szPath, szDir); fCopy &= ~FC_DEST_QUALIFIED; } else { ExpandFileName(szDir, szPath); }
if (szSource[0] == TEXT('#') && fCopy == FC_FILE) { fCopy = FC_SECTION; ++szSource; }
switch (fCopy) { case FC_SECTION: { szSource = infFindSection(NULL,szSource);
/*
* We are called even when the section doesn't exist */
if (szSource == NULL) { return ERROR_SUCCESS; }
fCopy = FC_LIST; } // fall through to FC_LIST
case FC_LIST: pFileBegin = szSource; cntFiles = infLineCount(szSource); break;
case FC_LISTTYPE: ListHead = List = (LPTSTR far *)szSource; pFileBegin = *ListHead; while ( *List++ ) // Count files to be copied.
++cntFiles; break;
case FC_FILE: case FC_QUALIFIED: default: pFileBegin = szSource; cntFiles = 1; }
/*
* walk all files in the list and call TryCopy .... * * NOTES: * we must walk file list sorted by disk number. * we should use the disk that is currently inserted. * we should do a find first/find next on the files???? * we need to check for errors. * we need to ask the user to insert disk in drive. * */
(*fpfnCopy)(COPY_START,0,NULL);
/*
* Go through all possible disks: 1 to 100 and A to Z (26) */
for (nDisk = 1; err == ERROR_SUCCESS && (cntFiles > 0) && (nDisk <= MAX_DISKS + 'Z' - 'A' + 1); nDisk++) { TCHAR Disk[10]; // Maximum string is "100:"
LPTSTR pFile; int FileNumber; // Which file in the list we're on
// (to pass to callback)
pFile = pFileBegin; // Start at first file
List = ListHead; // Handled chained lists
FileNumber = 0; // Informational for callback - gives
// which file in list we're on
/*
* Work out the string representing our disk letter */
if (nDisk > MAX_DISKS) { Disk[0] = TEXT('A') + nDisk - MAX_DISKS - 1; Disk[1] = TEXT('\0'); } else { _itow(nDisk, Disk, 10); }
wcscat(Disk, TEXT(":"));
for (; err == ERROR_SUCCESS && pFile; FileNumber++, pFile = fCopy == FC_LISTTYPE ? *(++List) : fCopy == FC_LIST ? infNextLine(pFile) : NULL) { /*
* We have to reset high bit of first byte because it could be set * by translating service in OEM setup to show that file name was * mapped */
*pFile = toascii(*pFile);
/*
* should we copy this file? * copy the files in disk order. */
if (_wcsnicmp(pFile, Disk, wcslen(Disk)) == 0 || // File has disk
// number and we're
// on that disk
RemoveDiskId(pFile) == pFile && nDisk == 1 && *pFile || // First disk and
// no disk number
fCopy == FC_QUALIFIED) { // Fully qualified
/*
* done with a file. decrement count. */
cntFiles--;
lstrcpy(szDrv, RemoveDiskId(pFile));
switch ((*fpfnCopy)(COPY_QUERYCOPY, FileNumber, pFile)) { case CopyCurrent: // Skip
continue;
case CopyNeither:
err = ERROR_FILE_EXISTS; // File already exists
case CopyNew: break;
default: break;
}
/*
* Pick up bad return code from switch */
if (err != ERROR_SUCCESS) { break; }
/*
* now we convert logical dest into a physical * (unless FC_QUALIFIED) */
infParseField(pFile, 1, szLogSrc); // logical source
if ( fCopy != FC_QUALIFIED ) { ExpandFileName(szLogSrc, szSrc); // full physical source
} else { lstrcpy(szSrc,szLogSrc); }
/*
* Attempt copy */
err = TryCopy(szSrc, // Qualified Source file
szLogSrc, // Logical source file name (with disk #)
szPath, // Path for directory to install in
fpfnCopy); // Copy callback function
/*
* If failed to find file try the windows directory */
if (err != ERROR_SUCCESS) { break; }
} /* End if dor if DoCopy */ } }
(*fpfnCopy)(COPY_END,err,NULL);
return err; }
/**********************************************************************
* * TryCopy * * Copy a single file from source to destination using the VerInstallFile * API - interpreting the return code as : * * ERROR_SUCCESS - OK * Other - failure type * **********************************************************************/
LONG TryCopy(LPTSTR szSrc, // Full expanded source file path
LPTSTR szLogSrc, // Logical source name
LPTSTR szDestPath, // Destination path
FPFNCOPY fpfnCopy) // Callback routine
{ DWORD wTmpLen; DWORD dwRetFlags; TCHAR szTempFile[MAX_PATH]; TCHAR szErrFile[MAX_PATH]; TCHAR DriversPath[MAX_PATH]; BOOL bRetVal; // Return code from callback
LPTSTR szFile; TCHAR szSrcPath[MAX_PATH]; int iAttemptCount; WORD wVerFlags; LONG err;
/*
* Fix up destination if file is a kernel driver */
if (IsFileKernelDriver(szSrc) && szDestPath) { wcscpy(DriversPath, szDestPath); wcscat(DriversPath, TEXT("\\drivers")); szDestPath = DriversPath; }
/*
* Create file name from current string */
szFile = FileName(szSrc); lstrcpy(szSrcPath, szSrc); StripPathName(szSrcPath);
for(iAttemptCount = 0, wVerFlags = 0 ; iAttemptCount <= MAX_COPY_ATTEMPTS; iAttemptCount++) {
HCURSOR hcurPrev; // Saved cursor state
// Central operation - attempt to install file szFile in directory
// pointed by szPath from directory pointed by szSrc
// If operation will fail but with possibility to force install
// in last parameter buffer we will have temporary file name ==>
// therefore we can avoid excessive copying.
// NOTE: now szFile consists of only file name and other buffers
// only path names.
wTmpLen = MAX_PATH;
hcurPrev = SetCursor(LoadCursor(NULL,IDC_WAIT)); dwRetFlags = VerInstallFile(wVerFlags, (LPTSTR) szFile, (LPTSTR) szFile, (LPTSTR) szSrcPath, (LPTSTR) szDestPath, (LPTSTR) szDestPath, (LPTSTR) szTempFile, (LPDWORD) &wTmpLen); SetCursor(hcurPrev);
/*
* Operation failed if at least one bit of return flags is non-zero * That is unusual but defined so in Version API. */
if ( !dwRetFlags ) return ERROR_SUCCESS; // If no errors - goto next file
/*
* If flag MISMATCH is set - install can be forced and we have * temporary file in destination subdirectory */
if ( dwRetFlags & VIF_MISMATCH ) {
if ( (dwRetFlags & VIF_SRCOLD) && (!bCopyEvenIfOlder) ) {
/*
* If we need not call back with question - automatically * force install with same parameters. * michaele, *only* if src file is *newer* than dst file */
DeleteFile(szTempFile);
return ERROR_SUCCESS; }
/*
* If we need not call back with question - automatically * force install with same parameters. */
wVerFlags |= VIFF_FORCEINSTALL; iAttemptCount--; // Make sure we get another go.
continue;
} /* End if MISMATCH */
/*
* If real error occured - call back with error file info * In all dialogs we use our error codes - so I will convert * flags returned from Ver API to ours. */
err = ConvertFlagToValue(dwRetFlags);
/*
* If source path or file is nor readable - try to change disk */
if ( dwRetFlags & VIF_CANNOTREADSRC ) { /*
* Now new path in szSrc so I deleted logic for creating it */
if (RemoveDiskId(szLogSrc) == szLogSrc)
/*
* if disk # not provided, default to 1 */
bRetVal = (*fpfnCopy)(COPY_INSERTDISK, (DWORD_PTR)"1", szSrcPath); else bRetVal = (*fpfnCopy)(COPY_INSERTDISK, (DWORD_PTR)szLogSrc, szSrcPath);
switch (bRetVal) { case FC_RETRY: continue; // and try again...
case FC_ABORT: return ERROR_FILE_NOT_FOUND;
case FC_IGNORE: break; } }
ExpandFileName(szLogSrc, szErrFile);
#if WINDOWSDIR
if (!*bWindowsDir && err != FC_ERROR_LOADED_DRIVER && err != ERROR_DISK_FULL) { GetWindowsDirectory(szPath, MAX_PATH); *bWindowsDir = TRUE; continue; }
#endif // WINDOWSDIR
switch ((*fpfnCopy)(COPY_ERROR, err, szErrFile)) {
case FC_IGNORE: return ERROR_SUCCESS;
case FC_RETRY: break;
case FC_ABORT: return ERROR_FILE_NOT_FOUND; } } // End of attempts
return err; }
/* BOOL GetDiskPath(Disk, szPath)
* * This function will retrive the full path name for a logical disk * * The code reads the [disks] section of SETUP.INF and looks for * n = path where n is the disk char. NOTE the disk '0' defaults to * the root windows directory. * * ENTRY: * * cDisk : what disk to find 0-9,A-Z * szPath : buffer to hold disk path * * Returns : * TRUE if a disk path was found * FALSE if there was no disk specified (ie no ':' * */
BOOL GetDiskPath(LPTSTR Disk, LPTSTR szPath) { TCHAR ach[MAX_PATH]; TCHAR szBuf[MAX_PATH]; int i;
/*
* Check to see if there is actually a disk id. * If not return FALSE */
if (RemoveDiskId(Disk) == Disk) { return FALSE; }
/*
* Create our copy of the disk id */
for (i = 0; Disk[i] != TEXT(':'); i++) { ach[i] = Disk[i]; } ach[i] = TEXT('\0');
/*
* Zero disk letter means windows setup directory */
if (_wcsicmp(ach, TEXT("0")) == 0) {
/*
* return the windows setup directory */
lstrcpy(szPath,szSetupPath); return TRUE; }
/*
* now look in the [disks] section for a full path name * * This is a pretty bogus concept and is not supported * in win 32 style disks section [Source Media Descriptions] */
if ( !infGetProfileString(NULL,DISK_SECT,ach,szPath) && !infGetProfileString(NULL,OEMDISK_SECT,ach,szPath)) {
lstrcpy(szPath, szDiskPath); } else { infParseField(szPath,1,szPath);
/*
* is the path relative? is so prepend the szDiskPath */
if (szPath[0] == TEXT('.') || szPath[0] == TEXT('\0')) { lstrcpy(szBuf,szDiskPath); catpath(szBuf,szPath); lstrcpy(szPath,szBuf); }
}
return TRUE; }
/* BOOL FAR PASCAL ExpandFileName(LPSTR szFile, LPTSTR szPath)
* * This function will retrive the full path name for a file * it will expand, logical disk letters to pyshical ones * will use current disk and directory if non specifed. * * if the drive specifed is 0-9, it will expand the drive into a * full pathname using GetDiskPath() * * IE 0:system ==> c:windows\system * 1:foo.txt a:\foo.txt * * ENTRY: * * szFile : File name to expand * szPath : buffer to hold full file name * */ BOOL ExpandFileName(LPTSTR szFile, LPTSTR szPath) { TCHAR szBuf[MAX_PATH*2];
if (GetDiskPath(szFile, szBuf)) { lstrcpy(szPath,szBuf); if (szFile[2]) catpath(szPath,szFile + 2); } else { lstrcpy(szPath,szFile); } return TRUE; }
void catpath(LPTSTR path, LPTSTR sz) { //
// Remove any drive letters from the directory to append
//
sz = RemoveDiskId(sz);
//
// Remove any current directories ".\" from directory to append
//
while (sz[0] == TEXT('.') && SLASH(sz[1])) sz += 2;
//
// Dont append a NULL string or a single "."
//
if (*sz && ! (sz[0] == TEXT('.') && sz[1] == 0)) { // Add a slash separator if necessary.
if ((! SLASH(path[lstrlen(path) - 1])) && // slash at end of path
((path[lstrlen(path) - 1]) != TEXT(':')) && // colon at end of path
(! SLASH(sz[0]))) // slash at beginning of file
lstrcat(path, CHSEPSTR);
lstrcat(path, sz); } }
/*
* Return a pointer to the file name part of a string */
LPTSTR FileName(LPTSTR szPath) { LPTSTR sz;
for (sz=szPath; *sz; sz++) ;
for (; sz>=szPath && !SLASH(*sz) && *sz!=TEXT(':'); sz--) ;
return ++sz; }
/*
* Return the portion of a file name following the disk (ie anything * before the colon). * If there is no colon just return a pointer to the original string */
LPTSTR RemoveDiskId(LPTSTR szPath) { LPTSTR sz;
for (sz = szPath; *sz; sz++) { if (*sz == TEXT(':')) { return sz + 1; } }
return szPath; }
LPTSTR StripPathName(LPTSTR szPath) { LPTSTR sz;
sz = FileName(szPath);
if (sz > szPath+1 && SLASH(sz[-1]) && sz[-2] != TEXT(':')) sz--;
*sz = 0; return szPath; }
/*
* See if a file is a kernel driver. Unfortunately the VersionInfo APIs * don't seem coded up to take care of this at the moment so we just check * to see if the file extension is ".SYS" */
BOOL IsFileKernelDriver(LPTSTR szPath) { TCHAR drive[MAX_PATH]; TCHAR dir[MAX_PATH]; TCHAR fname[MAX_PATH]; TCHAR ext[MAX_PATH];
lsplitpath(szPath, drive, dir, fname, ext); return !_wcsicmp(ext, TEXT(".sys")); }
/**************************************************************************
* * This function converts returned flags from Ver API to the numerical * error codes used in SETUP. * ***************************************************************************/
UINT ConvertFlagToValue(DWORD dwFlags) { if ( ! dwFlags ) return(NO_ERROR); if ( dwFlags & VIF_CANNOTREADSRC ) return(ERROR_FILE_NOT_FOUND); if ( dwFlags & VIF_OUTOFMEMORY ) return(ERROR_OUTOFMEMORY); if ( dwFlags & VIF_ACCESSVIOLATION ) return(ERROR_ACCESS_DENIED); if ( dwFlags & VIF_SHARINGVIOLATION ) return(ERROR_SHARING_VIOLATION); if ( dwFlags & VIF_FILEINUSE) return(FC_ERROR_LOADED_DRIVER);
return(ERROR_CANNOT_COPY); // General error
}
#ifdef CHECK_FLOPPY
/*--------------------------------------------------------------------------
IsValidDiskette() -
--------------------------------------------------------------------------*/
#define CBSECTORSIZE 512
#define INT13_READ 2
BOOL IsValidDiskette(int iDrive) { TCHAR buf[CBSECTORSIZE];
iDrive |= 0x0020; // make lower case
iDrive -= 'a'; // A = 0, B = 1, etc. for BIOS stuff
return MyReadWriteSector(buf, INT13_READ, iDrive, 0, 0, 1); }
/* BOOL IsDiskInDrive(char cDisk)
* * Is the specifed disk in the drive * * ENTRY: * * cDisk : what disk required to be in the drive (logical) * * return TRUE if the specifed disk is in the drive * FALSE if the wrong disk is in the drive or disk error * */ BOOL IsDiskInDrive(int iDisk) {
if ((iDisk >= 'A' && iDisk <= 'Z') || (iDisk >= 'a' && iDisk <= 'z')) { if (DosRemoveable(iDisk)) { if (!IsValidDiskette(iDisk)) return FALSE; } return TRUE; } return TRUE; // for non drive letters assume a path
// and thus always in.
}
#endif
|