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.
932 lines
25 KiB
932 lines
25 KiB
/*
|
|
* 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
|
|
|
|
LONG GetDiskPath(LPTSTR Disk, LPTSTR szPath, size_t cchPath);
|
|
|
|
// 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 {
|
|
err = ExpandFileName(szDir, szPath);
|
|
if (err != ERROR_SUCCESS)
|
|
{
|
|
(*fpfnCopy)(COPY_ERROR, err, szDir);
|
|
return err;
|
|
}
|
|
}
|
|
|
|
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)
|
|
*/
|
|
|
|
err = infParseField(pFile, 1, szLogSrc, SIZEOF(szLogSrc)); // logical source
|
|
if( INF_PARSE_FAILED(err) ) {
|
|
(*fpfnCopy)(COPY_ERROR, err, pFile);
|
|
break;
|
|
}
|
|
|
|
if ( fCopy != FC_QUALIFIED )
|
|
{
|
|
err = ExpandFileName(szLogSrc, szSrc); // full physical source
|
|
if (err != ERROR_SUCCESS) {
|
|
(*fpfnCopy)(COPY_ERROR, err, szLogSrc);
|
|
break;
|
|
}
|
|
} 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;
|
|
LONG lResult;
|
|
|
|
/*
|
|
* 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;
|
|
}
|
|
}
|
|
|
|
lResult = ExpandFileName(szLogSrc, szErrFile);
|
|
if (lResult != ERROR_SUCCESS)
|
|
{
|
|
(*fpfnCopy)(COPY_ERROR, lResult, szLogSrc);
|
|
return lResult;
|
|
}
|
|
|
|
#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;
|
|
}
|
|
|
|
/* LONG GetDiskPath(Disk, szPath, cchPath)
|
|
*
|
|
* 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
|
|
* cchPath : size of destination buffer (szPath) in characters.
|
|
* length must be large enough to hold all of the
|
|
* text including the null terminator.
|
|
*
|
|
* Returns :
|
|
* ERROR_SUCCESS if a disk path was found
|
|
* ERROR_INSUFFICIENT_BUFFER if szPath is too small to hold disk path
|
|
* ERROR_NOT_FOUND if there was no disk specified (ie no ':'
|
|
*
|
|
*/
|
|
|
|
LONG GetDiskPath(LPTSTR Disk, LPTSTR szPath, size_t cchPath)
|
|
{
|
|
TCHAR ach[MAX_PATH];
|
|
TCHAR szBuf[MAX_PATH];
|
|
LONG lResult;
|
|
int i;
|
|
|
|
|
|
/*
|
|
* Check to see if there is actually a disk id.
|
|
* If not return ERROR_NOT_FOUND
|
|
*/
|
|
|
|
if (RemoveDiskId(Disk) == Disk) {
|
|
return ERROR_NOT_FOUND;
|
|
}
|
|
|
|
/*
|
|
* 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 ERROR_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* 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]
|
|
*/
|
|
|
|
lResult = infGetProfileString(NULL,DISK_SECT,ach,szPath,cchPath);
|
|
if (ERROR_NOT_FOUND == lResult)
|
|
{
|
|
lResult = infGetProfileString(NULL,OEMDISK_SECT,ach,szPath,cchPath);
|
|
}
|
|
|
|
if (ERROR_SUCCESS == lResult)
|
|
{
|
|
lResult = infParseField(szPath,1,szPath,cchPath);
|
|
if( INF_PARSE_SUCCESS(lResult) )
|
|
{
|
|
/*
|
|
* 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);
|
|
}
|
|
lResult = ERROR_SUCCESS;
|
|
}
|
|
}
|
|
else if (ERROR_NOT_FOUND == lResult)
|
|
{
|
|
lstrcpy(szPath, szDiskPath);
|
|
lResult = ERROR_SUCCESS;
|
|
}
|
|
|
|
return lResult;
|
|
}
|
|
|
|
|
|
/* LONG 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
|
|
*
|
|
*/
|
|
LONG ExpandFileName(LPTSTR szFile, LPTSTR szPath)
|
|
{
|
|
TCHAR szBuf[MAX_PATH*2];
|
|
LONG lResult;
|
|
|
|
lResult = GetDiskPath(szFile, szBuf, SIZEOF(szBuf));
|
|
if (ERROR_SUCCESS == lResult)
|
|
{
|
|
lstrcpy(szPath,szBuf);
|
|
if (szFile[2])
|
|
catpath(szPath,szFile + 2);
|
|
}
|
|
else if (ERROR_NOT_FOUND == lResult)
|
|
{
|
|
lstrcpy(szPath,szFile);
|
|
lResult = ERROR_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
szPath[0] = 0;
|
|
}
|
|
return lResult;
|
|
}
|
|
|
|
|
|
|
|
|
|
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
|