982 lines
24 KiB
C
982 lines
24 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 1988-1999 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
ctools3.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
Low level utilities
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include "cmd.h"
|
||
|
|
||
|
struct envdata CmdEnv ; /* Holds info need to manipulate Cmd's environment */
|
||
|
|
||
|
extern unsigned tywild; /* type is wild flag @@5@J1 */
|
||
|
extern TCHAR CurDrvDir[], PathChar, Delimiters[] ;
|
||
|
|
||
|
extern TCHAR VolSrch[] ; /* M009 */
|
||
|
|
||
|
extern TCHAR BSlash ;
|
||
|
|
||
|
extern unsigned DosErr ;
|
||
|
|
||
|
/*** FullPath - build a full path name
|
||
|
*
|
||
|
* Purpose:
|
||
|
* See below.
|
||
|
*
|
||
|
* int FullPath(TCHAR * buf, TCHAR *fname)
|
||
|
*
|
||
|
* Args:
|
||
|
* buf - buffer to write full pathname into. (M017)
|
||
|
* fname - a file name and/or partial path
|
||
|
*
|
||
|
* Returns: (M017)
|
||
|
* FAILURE if malformed pathname (erroneous '.' or '..')
|
||
|
* SUCCESS otherwise
|
||
|
*
|
||
|
* Notes:
|
||
|
* - '.' and '..' are removed from the translated string (M017)
|
||
|
* - VERY BIG GOTCHA! Note that the 509 change can cause
|
||
|
* this rountine to modify the input filename (fname), because
|
||
|
* it strips quotes and copies it over the input filename.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
int FullPath(
|
||
|
TCHAR *buf,
|
||
|
TCHAR *fname,
|
||
|
ULONG sizpath
|
||
|
)
|
||
|
{
|
||
|
unsigned rc = SUCCESS; /* prime with good rc */
|
||
|
unsigned buflen; /* buffer length */
|
||
|
TCHAR *filepart;
|
||
|
DWORD rv;
|
||
|
|
||
|
mystrcpy(fname, StripQuotes(fname) );
|
||
|
|
||
|
if (*fname == NULLC) {
|
||
|
GetDir(buf,GD_DEFAULT);
|
||
|
buf += 2; /* Inc past drivespec */
|
||
|
buflen = mystrlen(buf); /* Is curdir root only? */
|
||
|
if (buflen >= MAX_PATH-3) { /* If too big then stop */
|
||
|
DosErr = ERROR_PATH_NOT_FOUND;
|
||
|
rc = FAILURE;
|
||
|
} else if (buflen != 1) { /* if not root then append */
|
||
|
*(buf+buflen++) = PathChar; /* ...a pathchar and... */
|
||
|
*(buf+buflen) = NULLC ; /* ...a null byte... */
|
||
|
} /* */
|
||
|
} else {
|
||
|
if ((mystrlen(fname) == 2) && (*(fname + 1) == COLON)) {
|
||
|
GetDir(buf,*fname); /* Get curdrvdir */
|
||
|
if ((buflen = mystrlen(buf)) > 3) {
|
||
|
*(buf+buflen++) = PathChar; /* ...a pathchar and... */
|
||
|
*(buf+buflen) = NULLC ; /* ...a null byte... */
|
||
|
}
|
||
|
} else {
|
||
|
DWORD dwOldMode;
|
||
|
|
||
|
dwOldMode = SetErrorMode(0);
|
||
|
SetErrorMode(SEM_FAILCRITICALERRORS);
|
||
|
rv = GetFullPathName( fname, sizpath, buf, &filepart );
|
||
|
SetErrorMode(dwOldMode);
|
||
|
if (!rv || rv > sizpath ) {
|
||
|
DosErr = ERROR_FILENAME_EXCED_RANGE;
|
||
|
rc = FAILURE;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return(rc);
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*** FileIsDevice - check a handle to see if it references a device
|
||
|
*
|
||
|
* Purpose:
|
||
|
* Return a nonzero value if fh is the file handle for a device.
|
||
|
* Otherwise, return 0.
|
||
|
*
|
||
|
* int FileIsDevice(int fh)
|
||
|
*
|
||
|
* Args:
|
||
|
* fh - the file handle to check
|
||
|
*
|
||
|
* Returns:
|
||
|
* See above.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
unsigned int flgwd;
|
||
|
|
||
|
int FileIsDevice( CRTHANDLE fh )
|
||
|
{
|
||
|
HANDLE hFile;
|
||
|
DWORD dwMode;
|
||
|
unsigned htype ;
|
||
|
|
||
|
hFile = CRTTONT(fh);
|
||
|
htype = GetFileType( hFile );
|
||
|
htype &= ~FILE_TYPE_REMOTE;
|
||
|
|
||
|
if (htype == FILE_TYPE_CHAR) {
|
||
|
//
|
||
|
// Simulate old behavior of this routine of setting the flgwd
|
||
|
// global variable with either 0, 1 or 2 to indicate if the
|
||
|
// passed handle is NOT a CON handle or is a CON input handle or
|
||
|
// is a CON output handle.
|
||
|
//
|
||
|
switch ( fh ) {
|
||
|
case STDIN:
|
||
|
hFile = GetStdHandle(STD_INPUT_HANDLE);
|
||
|
break;
|
||
|
case STDOUT:
|
||
|
hFile = GetStdHandle(STD_OUTPUT_HANDLE);
|
||
|
break;
|
||
|
case STDERR:
|
||
|
hFile = GetStdHandle(STD_ERROR_HANDLE);
|
||
|
break;
|
||
|
}
|
||
|
if (GetConsoleMode(hFile,&dwMode)) {
|
||
|
if (dwMode & (ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_ECHO_INPUT)) {
|
||
|
flgwd = 1;
|
||
|
} else if (dwMode & (ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT)) {
|
||
|
flgwd = 2;
|
||
|
}
|
||
|
} else {
|
||
|
flgwd = 0;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
} else {
|
||
|
flgwd = 0;
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int FileIsPipe( CRTHANDLE fh )
|
||
|
{
|
||
|
unsigned htype ;
|
||
|
|
||
|
htype = GetFileType( CRTTONT(fh) );
|
||
|
htype &= ~FILE_TYPE_REMOTE;
|
||
|
flgwd = 0;
|
||
|
return( htype == FILE_TYPE_PIPE ) ; /* @@4 */
|
||
|
}
|
||
|
|
||
|
int FileIsRemote( LPTSTR FileName )
|
||
|
{
|
||
|
LPTSTR p;
|
||
|
TCHAR Drive[MAX_PATH*2];
|
||
|
DWORD Length;
|
||
|
|
||
|
Length = GetFullPathName( FileName, sizeof(Drive)/sizeof(TCHAR), Drive, &p );
|
||
|
|
||
|
if (Length != 0 && Length < MAX_PATH * 2) {
|
||
|
Drive[3] = 0;
|
||
|
if (GetDriveType( Drive ) == DRIVE_REMOTE) {
|
||
|
return TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
int FileIsConsole(CRTHANDLE fh)
|
||
|
{
|
||
|
unsigned htype ;
|
||
|
DWORD dwMode;
|
||
|
HANDLE hFile;
|
||
|
|
||
|
hFile = CRTTONT(fh);
|
||
|
if (hFile == INVALID_HANDLE_VALUE) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
htype = GetFileType( hFile );
|
||
|
htype &= ~FILE_TYPE_REMOTE;
|
||
|
|
||
|
if ( htype == FILE_TYPE_CHAR ) {
|
||
|
|
||
|
switch ( fh ) {
|
||
|
case STDIN:
|
||
|
hFile = GetStdHandle(STD_INPUT_HANDLE);
|
||
|
break;
|
||
|
case STDOUT:
|
||
|
hFile = GetStdHandle(STD_OUTPUT_HANDLE);
|
||
|
break;
|
||
|
case STDERR:
|
||
|
hFile = GetStdHandle(STD_ERROR_HANDLE);
|
||
|
break;
|
||
|
}
|
||
|
if (GetConsoleMode(hFile,&dwMode)) {
|
||
|
return TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*** GetDir - get a current directory string
|
||
|
*
|
||
|
* Purpose:
|
||
|
* Get the current directory of the specified drive and put it in str.
|
||
|
*
|
||
|
* int GetDir(TCHAR *str, TCHAR dlet)
|
||
|
*
|
||
|
* Args:
|
||
|
* str - place to store the directory string
|
||
|
* dlet - the drive letter or 0 for the default drive
|
||
|
*
|
||
|
* Returns:
|
||
|
* 0 or 1 depending on the value of the carry flag after the CURRENTDIR
|
||
|
* system call/
|
||
|
*
|
||
|
* Notes:
|
||
|
* - M024 - If dlet is invalid, we leave the buffer as simply the
|
||
|
* null terminated root directory string.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
int GetDir(TCHAR *str, TCHAR dlet)
|
||
|
{
|
||
|
TCHAR denvname[ 4 ];
|
||
|
TCHAR *denvvalue;
|
||
|
|
||
|
if (dlet == GD_DEFAULT) {
|
||
|
GetCurrentDirectory(MAX_PATH, str);
|
||
|
return( SUCCESS );
|
||
|
}
|
||
|
|
||
|
denvname[ 0 ] = EQ;
|
||
|
denvname[ 1 ] = (TCHAR)_totupper(dlet);
|
||
|
denvname[ 2 ] = COLON;
|
||
|
denvname[ 3 ] = NULLC;
|
||
|
|
||
|
denvvalue = GetEnvVar( denvname );
|
||
|
if (!denvvalue) {
|
||
|
*str++ = (TCHAR)_totupper(dlet);
|
||
|
*str++ = COLON;
|
||
|
*str++ = BSLASH;
|
||
|
*str = NULLC;
|
||
|
return(FAILURE);
|
||
|
} else {
|
||
|
mystrcpy( str, denvvalue );
|
||
|
return(SUCCESS);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
FixupPath(
|
||
|
TCHAR *path,
|
||
|
BOOL fShortNames
|
||
|
)
|
||
|
{
|
||
|
TCHAR c, *src, *dst, *s;
|
||
|
int n, n1, length;
|
||
|
WIN32_FIND_DATA FindFileData;
|
||
|
HANDLE hFind;
|
||
|
|
||
|
length = _tcslen( path );
|
||
|
if (length > MAX_PATH) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
src = path + 3; // Skip root directory.
|
||
|
dst = path + 3;
|
||
|
do {
|
||
|
c = *src;
|
||
|
if (!c || c == PathChar) {
|
||
|
*src = NULLC;
|
||
|
hFind = FindFirstFile( path, &FindFileData );
|
||
|
*src = c;
|
||
|
if (hFind != INVALID_HANDLE_VALUE) {
|
||
|
FindClose( hFind );
|
||
|
if (FindFileData.cAlternateFileName[0] &&
|
||
|
(fShortNames ||
|
||
|
(!_tcsnicmp( FindFileData.cAlternateFileName, dst, (UINT)(src - dst)) &&
|
||
|
_tcsicmp( FindFileData.cFileName, FindFileData.cAlternateFileName)
|
||
|
)
|
||
|
)
|
||
|
)
|
||
|
//
|
||
|
// Use short name if requested or
|
||
|
// if input is explicitly using it and short name differs from long name
|
||
|
//
|
||
|
s = FindFileData.cAlternateFileName;
|
||
|
else
|
||
|
s = FindFileData.cFileName;
|
||
|
n = _tcslen( s );
|
||
|
n1 = n - (int)(src - dst);
|
||
|
|
||
|
//
|
||
|
// Make sure we don't overflow name
|
||
|
//
|
||
|
|
||
|
if (length + n1 > MAX_PATH) {
|
||
|
return FALSE;
|
||
|
} else {
|
||
|
length += n1;
|
||
|
}
|
||
|
|
||
|
if (n1 > 0) {
|
||
|
memmove( src+n1, src, _tcslen(src)*sizeof(TCHAR) );
|
||
|
src += n1;
|
||
|
}
|
||
|
|
||
|
_tcsncpy( dst, s, n );
|
||
|
dst += n;
|
||
|
_tcscpy( dst, src );
|
||
|
dst += 1;
|
||
|
src = dst;
|
||
|
} else {
|
||
|
src += 1;
|
||
|
dst = src;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
src += 1;
|
||
|
}
|
||
|
while (c != NULLC);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
/*** ChangeDirectory - change a current directory
|
||
|
*
|
||
|
* Purpose:
|
||
|
* Change the current directory on a drive. We do this either
|
||
|
* via changing the associated environment variable, or
|
||
|
* by changing the Win32 drive and directory.
|
||
|
*
|
||
|
* Args:
|
||
|
* newdir - directory (optionally w/drive)
|
||
|
* op - what operation should be performed
|
||
|
* CD_SET_DRIVE_DIRECTORY - set the Win32 current directory and drive
|
||
|
* CD_SET_DIRECTORY - set the Win32 current directory if the same drive
|
||
|
* CD_SET_ENV - set the environment variables for the current directory
|
||
|
* on a drive that's not the default drive.
|
||
|
*
|
||
|
* Returns:
|
||
|
* SUCCESS if the directory was changed.
|
||
|
* FAILURE otherwise.
|
||
|
*/
|
||
|
|
||
|
int ChangeDirectory(
|
||
|
TCHAR *newdir,
|
||
|
CHANGE_OP op
|
||
|
)
|
||
|
{
|
||
|
TCHAR denvname[ 4 ];
|
||
|
TCHAR newpath[ MAX_PATH + MAX_PATH ];
|
||
|
TCHAR denvvalue[ MAX_PATH ];
|
||
|
TCHAR c, *s;
|
||
|
DWORD attr;
|
||
|
DWORD newdirlength,length;
|
||
|
|
||
|
//
|
||
|
// UNC paths are not allowed
|
||
|
//
|
||
|
|
||
|
if (newdir[0] == PathChar && newdir[1] == PathChar)
|
||
|
return MSG_NO_UNC_CURDIR;
|
||
|
|
||
|
|
||
|
//
|
||
|
// truncate trailing spaces on ..
|
||
|
//
|
||
|
|
||
|
if (newdir[0] == DOT && newdir[1] == DOT) {
|
||
|
DWORD i, fNonBlank;
|
||
|
fNonBlank = 0;
|
||
|
newdirlength = mystrlen(newdir);
|
||
|
|
||
|
for (i=2; i<newdirlength; i++) {
|
||
|
if (newdir[i] != SPACE) {
|
||
|
fNonBlank = 1;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( ! fNonBlank) {
|
||
|
newdir[2] = NULLC;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Get current drive and directory in order to
|
||
|
// set up for forming the environment variable
|
||
|
//
|
||
|
|
||
|
GetCurrentDirectory( MAX_PATH, denvvalue );
|
||
|
c = (TCHAR)_totupper( denvvalue[ 0 ] );
|
||
|
|
||
|
//
|
||
|
// Convention for environment form is:
|
||
|
// Name of variable =d:
|
||
|
// value is full path including drive
|
||
|
//
|
||
|
|
||
|
denvname[ 0 ] = EQ;
|
||
|
if (_istalpha(*newdir) && newdir[1] == COLON) {
|
||
|
denvname[ 1 ] = (TCHAR)_totupper(*newdir);
|
||
|
newdir += 2;
|
||
|
} else {
|
||
|
denvname[ 1 ] = c;
|
||
|
}
|
||
|
denvname[ 2 ] = COLON;
|
||
|
denvname[ 3 ] = NULLC;
|
||
|
|
||
|
newdirlength = mystrlen(newdir);
|
||
|
if (*newdir == PathChar) {
|
||
|
if ((newdirlength+2) > sizeof(newpath)/sizeof( TCHAR )) {
|
||
|
return ERROR_FILENAME_EXCED_RANGE;
|
||
|
}
|
||
|
newpath[ 0 ] = denvname[ 1 ]; // drive
|
||
|
newpath[ 1 ] = denvname[ 2 ]; // colon
|
||
|
mystrcpy( &newpath[ 2 ], newdir );
|
||
|
} else {
|
||
|
if (s = GetEnvVar( denvname )) {
|
||
|
mystrcpy( newpath, s );
|
||
|
} else {
|
||
|
newpath[ 0 ] = denvname[ 1 ]; // drive
|
||
|
newpath[ 1 ] = denvname[ 2 ]; // colon
|
||
|
newpath[ 2 ] = NULLC;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Make sure there's exactly one backslash between newpath and newdir
|
||
|
//
|
||
|
|
||
|
s = lastc( newpath );
|
||
|
|
||
|
//
|
||
|
// s points to the last character or point to NUL (if newpath was
|
||
|
// zero length to begin with). A NULL means we drop in a path char
|
||
|
// over the NUL. A non-path char means we append a path char.
|
||
|
//
|
||
|
|
||
|
if (*s == NULLC) {
|
||
|
*s++ = PathChar;
|
||
|
} else if (*s != PathChar) {
|
||
|
s[1] = PathChar;
|
||
|
s += 2;
|
||
|
}
|
||
|
|
||
|
if (newdirlength + (s - newpath) > sizeof( newpath ) / sizeof( TCHAR )) {
|
||
|
return ERROR_FILENAME_EXCED_RANGE;
|
||
|
}
|
||
|
|
||
|
mystrcpy( s, newdir );
|
||
|
}
|
||
|
|
||
|
denvvalue[(sizeof( denvvalue )-1)/sizeof( TCHAR )] = NULLC;
|
||
|
|
||
|
//
|
||
|
// form the full path name
|
||
|
//
|
||
|
|
||
|
if ((length = GetFullPathName( newpath, (sizeof( denvvalue )-1)/sizeof( TCHAR ), denvvalue, &s ))==0) {
|
||
|
return( ERROR_ACCESS_DENIED );
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Remove any trailing backslash
|
||
|
//
|
||
|
|
||
|
if (s == NULL) {
|
||
|
s = denvvalue + _tcslen( denvvalue );
|
||
|
}
|
||
|
if (*s == NULLC && s > &denvvalue[ 3 ] && s[ -1 ] == PathChar) {
|
||
|
*--s = NULLC;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Verify that there won't be (initially) disk errors when we touch
|
||
|
// the directory
|
||
|
//
|
||
|
|
||
|
attr = GetFileAttributes( denvvalue );
|
||
|
if (attr == -1) {
|
||
|
attr = GetLastError( );
|
||
|
if (attr != ERROR_FILE_NOT_FOUND &&
|
||
|
attr != ERROR_PATH_NOT_FOUND &&
|
||
|
attr != ERROR_INVALID_NAME) {
|
||
|
return attr;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If extensions are enabled, fixup the path to have the same case as
|
||
|
// on disk
|
||
|
//
|
||
|
|
||
|
if (fEnableExtensions) {
|
||
|
if (!FixupPath( denvvalue, FALSE )) {
|
||
|
return ERROR_FILENAME_EXCED_RANGE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (op != CD_SET_ENV) {
|
||
|
attr = GetFileAttributes( denvvalue );
|
||
|
|
||
|
if (attr == (DWORD)-1 ||
|
||
|
!(attr & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_REPARSE_POINT))
|
||
|
) {
|
||
|
if ( attr == -1 ) {
|
||
|
attr = GetLastError();
|
||
|
if ( attr == ERROR_FILE_NOT_FOUND ) {
|
||
|
attr = ERROR_PATH_NOT_FOUND;
|
||
|
}
|
||
|
return attr;
|
||
|
}
|
||
|
return( ERROR_DIRECTORY );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If we're always setting the directory or
|
||
|
// if we're setting the directory if the drives are the same and
|
||
|
// the drives ARE the same
|
||
|
//
|
||
|
|
||
|
if (op == CD_SET_DRIVE_DIRECTORY
|
||
|
|| (op == CD_SET_DIRECTORY
|
||
|
&& c == denvname[ 1 ])) {
|
||
|
|
||
|
if (!SetCurrentDirectory( denvvalue )) {
|
||
|
return GetLastError();
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
if (SetEnvVar(denvname,denvvalue,&CmdEnv)) {
|
||
|
return( ERROR_NOT_ENOUGH_MEMORY );
|
||
|
}
|
||
|
GetDir(CurDrvDir, GD_DEFAULT) ;
|
||
|
|
||
|
return SUCCESS;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*** ChangeDir2 - change a current directory
|
||
|
*
|
||
|
* Purpose:
|
||
|
* To change to the directory specified in newdir on the drive specified
|
||
|
* in newdir. If no drive is given, the default drive is used. If the
|
||
|
* directory of the current drive is changed, the global variable
|
||
|
* CurDrvDir is updated.
|
||
|
*
|
||
|
* This routine is used by RestoreCurrentDirectories
|
||
|
*
|
||
|
* int ChangeDir2(BYTE *newdir, BOOL )
|
||
|
*
|
||
|
* Args:
|
||
|
* newdir - directory to change to
|
||
|
* BOOL - current drive
|
||
|
*
|
||
|
* Returns:
|
||
|
* SUCCESS if the directory was changed.
|
||
|
* FAILURE otherwise.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
int ChangeDir2(
|
||
|
TCHAR *newdir,
|
||
|
BOOL CurrentDrive
|
||
|
)
|
||
|
{
|
||
|
return ChangeDirectory( newdir, CurrentDrive ? CD_SET_DRIVE_DIRECTORY : CD_SET_ENV );
|
||
|
}
|
||
|
|
||
|
|
||
|
/*** ChangeDir - change a current directory
|
||
|
*
|
||
|
* Purpose:
|
||
|
* To change to the directory specified in newdir on the drive specified
|
||
|
* in newdir. If no drive is given, the default drive is used. If the
|
||
|
* directory of the current drive is changed, the global variable
|
||
|
* CurDrvDir is updated.
|
||
|
*
|
||
|
* int ChangeDir(TCHAR *newdir)
|
||
|
*
|
||
|
* Args:
|
||
|
* newdir - directory to change to
|
||
|
*
|
||
|
* Returns:
|
||
|
* SUCCESS if the directory was changed.
|
||
|
* FAILURE otherwise.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
int ChangeDir(
|
||
|
TCHAR *newdir
|
||
|
|
||
|
)
|
||
|
{
|
||
|
return ChangeDirectory( newdir, CD_SET_DIRECTORY );
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*** exists - Determine if a given file exists
|
||
|
*
|
||
|
* Purpose:
|
||
|
* To test the existence of a named file.
|
||
|
*
|
||
|
* int exists(TCHAR *filename)
|
||
|
*
|
||
|
* Args:
|
||
|
* filename - the filespec to test
|
||
|
*
|
||
|
* Returns:
|
||
|
* TRUE if file exists
|
||
|
* FALSE if it does not.
|
||
|
*
|
||
|
* Notes:
|
||
|
* M020 - Now uses ffirst to catch devices, directories and wildcards.
|
||
|
*/
|
||
|
|
||
|
exists(filename)
|
||
|
TCHAR *filename;
|
||
|
{
|
||
|
WIN32_FIND_DATA buf ; /* Use for ffirst/fnext */
|
||
|
HANDLE hn ;
|
||
|
int i ; /* tmp */
|
||
|
TCHAR FullPath[ 2 * MAX_PATH ];
|
||
|
TCHAR *p, *p1, SaveChar;
|
||
|
|
||
|
p = StripQuotes(filename);
|
||
|
i = GetFullPathName( p, 2 * MAX_PATH, FullPath, &p1 );
|
||
|
if (i) {
|
||
|
p = FullPath;
|
||
|
if (!_tcsncmp( p, TEXT("\\\\.\\"), 4 )) {
|
||
|
//
|
||
|
// If they gave us a device name, then see if they put something
|
||
|
// in front of it.
|
||
|
//
|
||
|
p += 4;
|
||
|
p1 = p;
|
||
|
if ((p1 = _tcsstr( filename, p )) && p1 > filename) {
|
||
|
//
|
||
|
// Something in front of the device name, so truncate the input
|
||
|
// path at the device name and see if that exists.
|
||
|
//
|
||
|
SaveChar = *p1;
|
||
|
*p1 = NULLC;
|
||
|
i = (int)GetFileAttributes( filename );
|
||
|
*p1 = SaveChar;
|
||
|
if (i != 0xFFFFFFFF) {
|
||
|
return i;
|
||
|
} else {
|
||
|
return 0;
|
||
|
}
|
||
|
} else {
|
||
|
//
|
||
|
// Just a device name given. See if it is valid.
|
||
|
//
|
||
|
i = (int)GetFileAttributes( filename );
|
||
|
if (i != 0xFFFFFFFF) {
|
||
|
return i;
|
||
|
} else {
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (p1 == NULL || *p1 == NULLC) {
|
||
|
i = (int)(GetFileAttributes( p ) != 0xFFFFFFFF);
|
||
|
} else {
|
||
|
i = ffirst( p, A_ALL, &buf, &hn );
|
||
|
findclose(hn);
|
||
|
if ( i == 0 ) {
|
||
|
//
|
||
|
// ffirst handles files & directories, but not
|
||
|
// root drives, so do special check for them.
|
||
|
//
|
||
|
if ( *(p+1) == (TCHAR)'\\' ||
|
||
|
(*(p+1) == (TCHAR)':' &&
|
||
|
*(p+2) == (TCHAR)'\\' &&
|
||
|
*(p+3) == (TCHAR)0
|
||
|
)
|
||
|
) {
|
||
|
UINT t;
|
||
|
t = GetDriveType( p );
|
||
|
if ( t > 1 ) {
|
||
|
i = 1;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return i;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*** exists_ex - Determine if a given executable file exists @@4
|
||
|
*
|
||
|
* Purpose:
|
||
|
* To test the existence of a named executable file.
|
||
|
*
|
||
|
* int exists_ex(TCHAR *filename)
|
||
|
*
|
||
|
* Args:
|
||
|
* filename - the filespec to test
|
||
|
* checkformeta - if TRUE, check for wildcard char
|
||
|
*
|
||
|
* Returns:
|
||
|
* TRUE if file exists
|
||
|
* FALSE if it does not.
|
||
|
*
|
||
|
* Notes:
|
||
|
* @@4 - Now uses ffirst to catch only files .
|
||
|
*/
|
||
|
|
||
|
exists_ex(filename,checkformeta) /*@@4*/
|
||
|
TCHAR *filename; /*@@4*/
|
||
|
BOOL checkformeta;
|
||
|
{ /*@@4*/
|
||
|
WIN32_FIND_DATA buf; /* use for ffirst/fnext */
|
||
|
HANDLE hn;
|
||
|
int i;
|
||
|
TCHAR *ptr;
|
||
|
|
||
|
/* can not execute wild card files, so check for those first */
|
||
|
|
||
|
if (checkformeta && (mystrchr( filename, STAR ) || mystrchr( filename, QMARK ))) {
|
||
|
DosErr = 3;
|
||
|
i = 0;
|
||
|
} else {
|
||
|
|
||
|
/* see if the file exists, do not include Directory, volume, or */
|
||
|
/* hidden files */
|
||
|
i = ((ffirst( filename , A_AEDV, &buf, &hn))) ;
|
||
|
|
||
|
if ( i ) {
|
||
|
findclose(hn) ;
|
||
|
|
||
|
/* if the file exists then copy the file name, to get the case */
|
||
|
ptr = mystrrchr( filename, BSLASH );
|
||
|
if ( ptr == NULL ) {
|
||
|
ptr = filename;
|
||
|
if ( mystrlen( ptr ) > 2 && ptr[1] == COLON ) {
|
||
|
ptr = &filename[2];
|
||
|
}
|
||
|
} else {
|
||
|
ptr++;
|
||
|
}
|
||
|
mystrcpy( ptr, buf.cFileName);
|
||
|
} else if ( DosErr == 18 ) {
|
||
|
DosErr = 2;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
return(i) ; /*@@4*/
|
||
|
} /*@@4*/
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*** FixPChar - Fix up any leading path in a string
|
||
|
*
|
||
|
* Purpose:
|
||
|
* To insure that paths match the current Swit/Pathchar setting
|
||
|
*
|
||
|
* void FixPChar(TCHAR *str, TCHAR PChar)
|
||
|
*
|
||
|
* Args:
|
||
|
* str - the string to fixup
|
||
|
* Pchar - character to replace
|
||
|
*
|
||
|
* Returns:
|
||
|
* Nothing
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
void FixPChar(TCHAR *str, TCHAR PChar)
|
||
|
{
|
||
|
TCHAR *sptr1, /* Index for string */
|
||
|
*sptr2 ; /* Change marker */
|
||
|
|
||
|
sptr1 = str ; /* Init to start of string */
|
||
|
|
||
|
while (sptr2 = mystrchr(sptr1,PChar)) {
|
||
|
*sptr2++ = PathChar ;
|
||
|
sptr1 = sptr2 ;
|
||
|
} ;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*** FlushKB - Remove extra unwanted input from Keyboard
|
||
|
*
|
||
|
* Purpose:
|
||
|
* To perform a keyboard flush up to the next CR/LF.
|
||
|
*
|
||
|
* FlushKB()
|
||
|
*
|
||
|
* Args:
|
||
|
* None
|
||
|
*
|
||
|
* Returns:
|
||
|
* Nothing
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
void FlushKB()
|
||
|
{
|
||
|
DWORD cnt;
|
||
|
TCHAR IgnoreBuffer[128];
|
||
|
|
||
|
while (ReadBufFromInput( GetStdHandle(STD_INPUT_HANDLE), IgnoreBuffer, 128, &cnt )) {
|
||
|
if (mystrchr( IgnoreBuffer, CR ))
|
||
|
return ;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*** DriveIsFixed - Determine if drive is removeable media
|
||
|
*
|
||
|
* Purpose: @@4
|
||
|
* To determine if the input drive is a removeable media.
|
||
|
*
|
||
|
* DriveIsFixed(TCHAR *drive_ptr )
|
||
|
*
|
||
|
* Args:
|
||
|
* drive_ptr - pointer to a file name that contains a drive
|
||
|
* specification.
|
||
|
*
|
||
|
* Returns:
|
||
|
* 1 - if error or non removeable media
|
||
|
* 0 - if no error and removeable media
|
||
|
*/
|
||
|
|
||
|
int
|
||
|
DriveIsFixed( TCHAR *drive_ptr )
|
||
|
{
|
||
|
unsigned rc = 0;
|
||
|
TCHAR drive_spec[3];
|
||
|
|
||
|
drive_spec[0] = *drive_ptr;
|
||
|
drive_spec[1] = COLON;
|
||
|
drive_spec[2] = NULLC;
|
||
|
|
||
|
// FIX, FIX - use GetVolumeInfo, disabling hard errors?
|
||
|
|
||
|
if ((*drive_ptr == TEXT('A')) || (*drive_ptr == TEXT('B'))) {
|
||
|
rc = 0;
|
||
|
} else {
|
||
|
rc = 1;
|
||
|
}
|
||
|
|
||
|
return( rc );
|
||
|
}
|
||
|
|
||
|
int
|
||
|
CmdPutChars(
|
||
|
PTCHAR String,
|
||
|
int Length
|
||
|
)
|
||
|
{
|
||
|
int rc = SUCCESS; /* return code */
|
||
|
int bytesread; /* bytes to write count */
|
||
|
int byteswrit; /* bytes written count */
|
||
|
BOOL flag;
|
||
|
|
||
|
if (Length > 0) {
|
||
|
|
||
|
if (FileIsConsole(STDOUT)) {
|
||
|
if (!(flag=WriteConsole(CRTTONT(STDOUT), String, Length, &byteswrit, NULL)))
|
||
|
rc = GetLastError();
|
||
|
} else {
|
||
|
Length *= sizeof(TCHAR);
|
||
|
flag = MyWriteFile( STDOUT, (CHAR *)String, Length, &byteswrit);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If the write failed or unable to output all the data
|
||
|
//
|
||
|
|
||
|
if (flag == 0 || byteswrit != Length) {
|
||
|
rc = GetLastError();
|
||
|
|
||
|
//
|
||
|
// No error => DiskFull
|
||
|
//
|
||
|
|
||
|
if (rc == 0) {
|
||
|
rc = ERROR_DISK_FULL;
|
||
|
}
|
||
|
|
||
|
if (FileIsDevice(STDOUT)) {
|
||
|
//
|
||
|
// If the we were writing to a device then the error is a device
|
||
|
// write fault.
|
||
|
//
|
||
|
|
||
|
PutStdErr( ERROR_WRITE_FAULT, NOARGS );
|
||
|
} else if (FileIsPipe(STDOUT)) {
|
||
|
|
||
|
//
|
||
|
// If the we were writing to a pipe, then the error is an invalid
|
||
|
// pipe error.
|
||
|
//
|
||
|
|
||
|
PutStdErr(MSG_CMD_INVAL_PIPE, NOARGS);
|
||
|
return(FAILURE);
|
||
|
} else {
|
||
|
//
|
||
|
// Just output the error we found
|
||
|
//
|
||
|
|
||
|
PrtErr(rc);
|
||
|
return(FAILURE);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return(rc);
|
||
|
}
|
||
|
|
||
|
|
||
|
int
|
||
|
CmdPutString(
|
||
|
PTCHAR String
|
||
|
)
|
||
|
{
|
||
|
return CmdPutChars( String, _tcslen( String ));
|
||
|
}
|
||
|
|
||
|
|
||
|
int
|
||
|
cmd_printf(
|
||
|
TCHAR *fmt,
|
||
|
...
|
||
|
)
|
||
|
{
|
||
|
int Length;
|
||
|
va_list arg_ptr;
|
||
|
|
||
|
va_start(arg_ptr,fmt);
|
||
|
|
||
|
Length = _vsntprintf( MsgBuf, MAXCBMSGBUFFER, fmt, arg_ptr );
|
||
|
|
||
|
va_end(arg_ptr);
|
||
|
|
||
|
return CmdPutChars( MsgBuf, Length );
|
||
|
}
|