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.
673 lines
24 KiB
673 lines
24 KiB
/*++
|
|
|
|
Copyright (c) 1988-1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
ctools1.c
|
|
|
|
Abstract:
|
|
|
|
Low level utilities
|
|
|
|
--*/
|
|
|
|
#include "cmd.h"
|
|
|
|
extern unsigned tywild; /* type is wild flag */
|
|
extern TCHAR CurDrvDir[], *SaveDir, PathChar, Delimiters[] ;
|
|
|
|
extern TCHAR VolSrch[] ;
|
|
|
|
extern TCHAR BSlash ;
|
|
|
|
extern unsigned DosErr ;
|
|
|
|
extern BOOL CtrlCSeen;
|
|
|
|
static TCHAR szNull[] = TEXT("");
|
|
|
|
|
|
/*** TokStr - tokenize argument strings
|
|
*
|
|
* Purpose:
|
|
* Tokenize a string.
|
|
* Allocate space for a new string and copy each token in src into the
|
|
* new string and null terminate it. Tokens are whitespace delimited
|
|
* unless changed by specialdelims and/or tsflags. The entire tokenized
|
|
* string ends with 2 null bytes.
|
|
*
|
|
* TCHAR *TokStr(TCHAR *src, TCHAR *specialdelims, unsigned tsflags)
|
|
*
|
|
* Args:
|
|
* src - the string to be tokenized
|
|
* specialdelims - a string of other characters which are to be comsidered
|
|
* as token delimiters
|
|
* tsflags - bit 0 nonzero if whitespace are NOT delimiters
|
|
* bit 1 nonzero if special delimiters are tokens themselves,
|
|
* eg "foo=bar" => "foo0=0bar00"
|
|
*
|
|
* Returns:
|
|
* A pointer to the new string.
|
|
* A pointer to a null string if src is NULL
|
|
* NULL if unable to allocate memory.
|
|
*
|
|
* Notes:
|
|
* The format of the tokenized string dictates the way code is written
|
|
* to process the tokens in that string. For instance, the code
|
|
* "s += mystrlen(s)+1" is the way to update s to point to the next token
|
|
* in the string.
|
|
*
|
|
* Command considers "=", ",", and ";" to be token delimiters just like
|
|
* whitespace. The only time they are not treated like whitespace is
|
|
* when they are included in specialdelims.
|
|
*
|
|
* *** W A R N I N G ! ***
|
|
* THIS ROUTINE WILL CAUSE AN ABORT IF MEMORY CANNOT BE ALLOCATED
|
|
* THIS ROUTINE MUST NOT BE CALLED DURING A SIGNAL
|
|
* CRITICAL SECTION OR DURING RECOVERY FROM AN ABORT
|
|
*
|
|
*/
|
|
|
|
TCHAR *TokStr(src, specialdelims, tsflags)
|
|
TCHAR *src ;
|
|
TCHAR *specialdelims ;
|
|
unsigned tsflags ;
|
|
{
|
|
TCHAR *ts ; /* Tokenized string pointer */
|
|
TCHAR *tscpy, /* Copy of ts */
|
|
delist[5], /* List of non-whitespace delimiter/separators */
|
|
c; /* Work variable */
|
|
|
|
int first, /* Flag, true if first time through the loop */
|
|
lctdelim, /* Flag, true if last byte was token delimiter */
|
|
i, j ; /* Index/loop counter */
|
|
|
|
DEBUG((CTGRP, TSLVL, "TOKSTR: Entered &src = %04x, src = %ws",src,src));
|
|
DEBUG((CTGRP, TSLVL, "TOKSTR: Making copy str of len %d",(mystrlen(src)*2+2))) ;
|
|
|
|
if (src == NULL) {
|
|
return(szNull); // This routine returns a doubly null terminated string
|
|
} else {
|
|
ts = tscpy = gmkstr((mystrlen(src)*2+2)*sizeof(TCHAR)) ; /*WARNING*/
|
|
|
|
DEBUG((CTGRP, TSLVL, "TOKSTR: &tscpy = %04x",tscpy)) ;
|
|
|
|
for (i = j = 0 ; c = *(&Delimiters[i]) ; i++)
|
|
if (!mystrchr(specialdelims, c))
|
|
delist[j++] = c ;
|
|
delist[j] = NULLC ;
|
|
|
|
DEBUG((CTGRP, TSLVL, "TOKSTR: Delimiter string built as `%ws'",delist)) ;
|
|
|
|
for (first = TRUE, lctdelim = TRUE ; *src ; src++) {
|
|
|
|
if (
|
|
(*src != QUOTE) &&
|
|
(_istspace(*src) || mystrchr(delist, *src)) &&
|
|
(!(tsflags & TS_WSPACE) || first) &&
|
|
(!(tsflags & TS_SDTOKENS) || !mystrchr(specialdelims, *src)) &&
|
|
(!(tsflags & TS_NWSPACE) || !mystrchr(specialdelims, *src)) ) {
|
|
|
|
while ( *src &&
|
|
(*src != QUOTE) &&
|
|
(_istspace(*src) || mystrchr(delist, *src)) &&
|
|
(!(tsflags & TS_SDTOKENS) || !mystrchr(specialdelims, *src)) &&
|
|
(!(tsflags & TS_NWSPACE) || !mystrchr(specialdelims, *src)) )
|
|
src++ ;
|
|
|
|
if (!(*src))
|
|
break ;
|
|
|
|
if (!first && !lctdelim)
|
|
ts++ ;
|
|
|
|
lctdelim = TRUE ;
|
|
} ;
|
|
|
|
first = FALSE ;
|
|
|
|
if (specialdelims && mystrchr(specialdelims, *src)) {
|
|
if (tsflags & TS_SDTOKENS) {
|
|
if (lctdelim)
|
|
*ts = *src ;
|
|
else
|
|
*++ts = *src ;
|
|
lctdelim = TRUE ;
|
|
ts++ ;
|
|
} else {
|
|
if ( tsflags & TS_NWSPACE )
|
|
*ts = *src ;
|
|
lctdelim = FALSE ;
|
|
}
|
|
|
|
ts++ ;
|
|
continue ;
|
|
} ;
|
|
|
|
*ts++ = *src ;
|
|
if ( *src == QUOTE ) {
|
|
do {
|
|
*ts++ = *(++src);
|
|
} while ( src[0] && src[0] != QUOTE && src[1] );
|
|
if ( !src[0] ) {
|
|
src--;
|
|
}
|
|
}
|
|
|
|
lctdelim = FALSE ;
|
|
} ;
|
|
|
|
DEBUG((CTGRP, TSLVL, "TOKSTR: String complete, resizing to %d",ts-tscpy+2)) ;
|
|
|
|
return(resize(tscpy, ((UINT)(ts-tscpy)+2)*sizeof(TCHAR))) ;
|
|
|
|
DEBUG((CTGRP, TSLVL, "TOKSTR: Resizing done, returning")) ;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
/* */
|
|
/* LoopThroughArgs - call a function on all args in a list */
|
|
/* */
|
|
/* Purpose: */
|
|
/* This is function is called by many of the commands that take */
|
|
/* multiple arguments. This function will parse the argument string, */
|
|
/* complain if no args were given, and call func on each of the ards */
|
|
/* in argstr. Optionally, it will also expand any wildcards in the */
|
|
/* arguments. Execution stops if func ever returns FAILURE. */
|
|
/* */
|
|
/* int LoopThroughArgs(TCHAR *argstr, int (*func)(), int ltaflags) */
|
|
/* */
|
|
/* Args: */
|
|
/* argstr - argument string */
|
|
/* func - the function to pass each element of argstr */
|
|
/* ltaflags - bit 0 on if wildcards are to be expanded */
|
|
/* bit 1 on if it's ok for argstr to be empty (nothing but whitespace) */
|
|
/* bit 2 on if file names should be passed through un changed */
|
|
/* when the wildcard expansion fails to find any matches.*/
|
|
/* */
|
|
/* Returns: */
|
|
/* The value returned by func the last time it is run. */
|
|
/* */
|
|
/******************************************************************************/
|
|
|
|
int LoopThroughArgs(argstr, func, ltaflags)
|
|
TCHAR *argstr ;
|
|
PLOOP_THROUGH_ARGS_ROUTINE func ;
|
|
int ltaflags ;
|
|
{
|
|
TCHAR *tas ; /* Tokenized argument string */
|
|
TCHAR fspec[MAX_PATH] ; /* Holds filespec when expanding */
|
|
WIN32_FIND_DATA buf ; /* Use for ffirst/fnext */
|
|
HANDLE hnFirst ;
|
|
CPYINFO fsinfo ;
|
|
int catspot ; /* Fspec index where fname should be added */
|
|
unsigned final_code = SUCCESS;
|
|
unsigned error_code = SUCCESS;
|
|
int multargs = FALSE;
|
|
unsigned attr;/* attribute for ffirst for because of TYPE wild */
|
|
unsigned taslen;
|
|
|
|
|
|
tywild = FALSE; /* global type wild card flag ret */
|
|
|
|
GetDir(CurDrvDir, GD_DEFAULT);
|
|
|
|
if (*(tas = TokStr(argstr, NULL, TS_NOFLAGS)) == NULLC)
|
|
{
|
|
if (ltaflags & LTA_NULLOK)
|
|
{
|
|
/* return((*func)(tas)) ; */
|
|
return((*func)( StripQuotes(tas) )) ;
|
|
}
|
|
|
|
PutStdErr(MSG_BAD_SYNTAX, NOARGS);
|
|
return(FAILURE) ;
|
|
}
|
|
|
|
if (*(tas + mystrlen(tas) + 1) ) /* Check for multiple args */
|
|
{
|
|
multargs = TRUE;
|
|
}
|
|
|
|
for ( ; *tas ; tas += taslen+1 )
|
|
{
|
|
if (CtrlCSeen) {
|
|
return(FAILURE);
|
|
}
|
|
taslen = mystrlen( tas );
|
|
mystrcpy( tas, StripQuotes( tas ) );
|
|
|
|
if (ltaflags & LTA_EXPAND)
|
|
{
|
|
if (cmdfound == TYTYP) /* if TYPE cmd then only files */
|
|
{
|
|
attr = FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_ARCHIVE;
|
|
}
|
|
else /* else */
|
|
{
|
|
attr = A_ALL; /* find all */
|
|
}
|
|
//
|
|
// this is used to detect an error other then can not
|
|
// find file. It is set in ffirst
|
|
//
|
|
DosErr = 0;
|
|
if (!ffirst(tas, attr, &buf, &hnFirst))
|
|
{
|
|
//
|
|
// Check that failure was not do to some system error such
|
|
// as an abort on access to floppy
|
|
//
|
|
if (DosErr) {
|
|
|
|
if ((DosErr != ERROR_FILE_NOT_FOUND) &&
|
|
(DosErr != ERROR_NO_MORE_FILES)) {
|
|
|
|
PutStdErr(DosErr, NOARGS);
|
|
|
|
return( FAILURE );
|
|
|
|
}
|
|
}
|
|
|
|
if (ltaflags & LTA_NOMATCH)
|
|
{
|
|
if ( error_code = ((*func)(tas)) )
|
|
{
|
|
final_code = FAILURE;
|
|
if (multargs) /* if cmd failed then (TYPE)*/
|
|
{ /* display arg failed msg too */
|
|
PutStdErr( MSG_ERR_PROC_ARG, ONEARG, tas );
|
|
}
|
|
}
|
|
if ( error_code && !(ltaflags & LTA_CONT))
|
|
{
|
|
return(FAILURE) ;
|
|
}
|
|
else
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
PutStdErr(((DosErr == ERROR_PATH_NOT_FOUND) ?
|
|
MSG_REN_INVAL_PATH_FILENAME :
|
|
ERROR_FILE_NOT_FOUND),
|
|
NOARGS);
|
|
return(FAILURE) ;
|
|
}
|
|
|
|
if (buf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
|
{
|
|
PutStdErr(MSG_REN_INVAL_PATH_FILENAME, NOARGS);
|
|
return(FAILURE) ;
|
|
}
|
|
|
|
fsinfo.fspec = tas ;
|
|
ScanFSpec(&fsinfo) ;
|
|
catspot = (int)(fsinfo.fnptr-tas) ;
|
|
mystrcpy(fspec, tas) ;
|
|
|
|
do
|
|
{
|
|
fspec[catspot] = NULLC ;
|
|
tywild |= multargs; /* if multiple args or wild then wild for TYPE */
|
|
if ( error_code = ((*func)(mystrcat(fspec, buf.cFileName))) )
|
|
{
|
|
final_code = FAILURE;
|
|
}
|
|
if ( error_code && !(ltaflags & LTA_CONT))
|
|
{
|
|
return(FAILURE) ;
|
|
}
|
|
} while(fnext(&buf, attr, hnFirst));
|
|
|
|
findclose(hnFirst) ;
|
|
}
|
|
else
|
|
{
|
|
tywild |= multargs; /* if multiple args or wild then wild for TYPE */
|
|
/* if ( error_code = ((*func)(mystrcpy(fspec,tas))) ) */
|
|
if ( error_code = ((*func)(tas)) )
|
|
{
|
|
final_code = FAILURE;
|
|
}
|
|
if ( error_code && !(ltaflags & LTA_CONT))
|
|
{
|
|
return(FAILURE) ;
|
|
}
|
|
}
|
|
|
|
if (error_code && multargs) /* error this time through */
|
|
{
|
|
PutStdErr(MSG_ERR_PROC_ARG, ONEARG, tas );
|
|
}
|
|
}
|
|
return( final_code ) ;
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN
|
|
IsDriveNameOnly (
|
|
IN PTCHAR psz
|
|
)
|
|
{
|
|
|
|
//
|
|
// If it does not have any path character, is 2 chars long and
|
|
// has a ':' it must be a drive
|
|
//
|
|
if (!mystrrchr(psz,PathChar)) {
|
|
if ((mystrlen(psz) == 2) && psz[1] == COLON) {
|
|
return( TRUE );
|
|
}
|
|
}
|
|
return( FALSE );
|
|
}
|
|
|
|
|
|
/*** ScanFSpec - parse a path string
|
|
*
|
|
* Purpose:
|
|
* To scan the filespec in cis to find the information needed to set the
|
|
* pathend, fnptr, extptr, and flags field of the structure. Pathend is
|
|
* a ptr to the end of the path and can be NULL. Fnptr is a ptr to the
|
|
* filename and may point to a null character. Extptr is a ptr to the
|
|
* extension (including ".") and may point to a null character.
|
|
*
|
|
* ScanFSpec(PCPYINFO cis)
|
|
*
|
|
* Arg:
|
|
* cis - the copy information structure to fill
|
|
*
|
|
* Notes:
|
|
* This function needs to be rewritten and cleanup more than any other
|
|
* function in the entire program!!!
|
|
*
|
|
* *** W A R N I N G ! ***
|
|
* THIS ROUTINE WILL CAUSE AN ABORT IF MEMORY CANNOT BE ALLOCATED
|
|
* THIS ROUTINE MUST NOT BE CALLED DURING A SIGNAL
|
|
* CRITICAL SECTION OR DURING RECOVERY FROM AN ABORT
|
|
*
|
|
*/
|
|
|
|
BOOL ScanFSpec(cis)
|
|
PCPYINFO cis ;
|
|
{
|
|
unsigned att ;
|
|
UINT OldErrorMode;
|
|
|
|
TCHAR *sds = &VolSrch[2] ; /* "\*.*" Added to dir's */
|
|
|
|
TCHAR *fspec ; /* Work Vars - Holds filespec */
|
|
TCHAR *wptr ; /* - General string pointer */
|
|
TCHAR c ; /* - Temp byte holder */
|
|
TCHAR c2 = NULLC ; /* Another if two are needed */
|
|
int cbPath, /* - Length of incoming fspec */
|
|
dirflag = FALSE ; /* - FSpec is directory flag */
|
|
CRTHANDLE hn;
|
|
PWIN32_FIND_DATA pfdSave;
|
|
|
|
DosErr = NO_ERROR;
|
|
DEBUG((CTGRP, SFLVL, "SCANFSPEC: cis = %04x fspec = %04x `%ws'",
|
|
cis, cis->fspec, cis->fspec)) ;
|
|
|
|
cbPath = mystrlen(cis->fspec) ; /* Get length of filespec */
|
|
|
|
if (*(wptr = lastc(cis->fspec)) == COLON && cbPath > 2) {
|
|
*wptr-- = NULLC ; /* Zap colon if device name */
|
|
|
|
OldErrorMode = SetErrorMode( 0 );
|
|
hn = Copen(cis->fspec, O_RDONLY|O_BINARY );
|
|
if ((hn == BADHANDLE) || (!FileIsDevice(hn) && !FileIsPipe(hn))) {
|
|
*++wptr = COLON;
|
|
if (cmdfound == CPYTYP) {
|
|
if (cpydest == FALSE) {
|
|
PutStdErr( MSG_CMD_NOT_RECOGNIZED, ONEARG, cis->fspec);
|
|
}
|
|
cdevfail = TRUE;
|
|
} else {
|
|
PutStdErr( MSG_CMD_NOT_RECOGNIZED, ONEARG, cis->fspec);
|
|
}
|
|
if (hn != BADHANDLE) {
|
|
Cclose( hn );
|
|
}
|
|
|
|
} else {
|
|
if ( FileIsDevice(hn) || FileIsPipe(hn) ) {
|
|
Cclose( hn );
|
|
}
|
|
}
|
|
SetErrorMode( OldErrorMode );
|
|
}
|
|
|
|
cis->buf = (PWIN32_FIND_DATA)gmkstr(sizeof(WIN32_FIND_DATA)) ; /*WARNING*/
|
|
|
|
/* First it must be determined if this is a file or directory and if directory
|
|
* a "\*.*" appended. Filespec's that are "." or "\" or those ending in "\",
|
|
* ":.", ".." or "\." are assumed to be directories. Note that ROOT will fit
|
|
* one of these patterns if explicitly named. If no such pattern is found,
|
|
* a Get Attributes system call is performed as a final test. Note that
|
|
* wildcards are not tested for, since the DOS call will fail defaulting them
|
|
* to filenames. Success of any test assumes directory with the "\*.*" being
|
|
* appended, while failure of all tests assumes filename.
|
|
*/
|
|
|
|
/* If the filespec ends in a '\' set dirflag. Otherwise find where the
|
|
* actual filename begins (by looking for last PathChar if there is one).
|
|
* If there is no pathchar, then check if a drive and colon has been
|
|
* specified. Update the pointer to point to the actual file name spec.
|
|
* If it is a "." or ".." then set dirflag.
|
|
*/
|
|
c = *wptr;
|
|
if ( c == PathChar ) {
|
|
dirflag = TRUE ;
|
|
} else {
|
|
wptr = mystrrchr(cis->fspec, PathChar);
|
|
if (wptr == NULL) {
|
|
wptr = cis->fspec ;
|
|
if ((mystrlen(wptr) >= 2) && (wptr[1] == COLON)) {
|
|
wptr = &wptr[2];
|
|
}
|
|
} else {
|
|
wptr++ ;
|
|
}
|
|
if ((_tcsicmp(wptr, TEXT(".")) == 0) || (_tcsicmp(wptr, TEXT("..")) == 0)) {
|
|
dirflag = TRUE ;
|
|
}
|
|
}
|
|
|
|
if (!dirflag) {
|
|
if (cmdfound == CPYTYP) { /* bypass if COPY cmd */
|
|
if (cpydflag == TRUE) {
|
|
att = GetFileAttributes(cis->fspec);
|
|
DosErr = (att != -1 ? NO_ERROR : GetLastError());
|
|
if (att != -1 ) {
|
|
if (att & FILE_ATTRIBUTE_DIRECTORY) {
|
|
dirflag = TRUE;
|
|
}
|
|
}
|
|
} else {
|
|
if (cpyfirst == TRUE) { /* and !first time */
|
|
cpyfirst = FALSE; /* and !first time */
|
|
att = GetFileAttributes(cis->fspec);
|
|
DosErr = (att != -1 ? NO_ERROR : GetLastError());
|
|
if (att != -1 ) {
|
|
if (att & FILE_ATTRIBUTE_DIRECTORY) {
|
|
dirflag = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
att = GetFileAttributes(cis->fspec);
|
|
DosErr = (att != -1 ? NO_ERROR : GetLastError());
|
|
if (att != -1 ) {
|
|
if (att & FILE_ATTRIBUTE_DIRECTORY) {
|
|
dirflag = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Note that in the following conditional, the directory attribute is set
|
|
* in cis->buf->attributes. Some functions calling ScanFSpec() require this
|
|
* knowledge.
|
|
*/
|
|
if (dirflag) {
|
|
if (c == PathChar) /* If ending in "\"... */
|
|
{
|
|
sds = &VolSrch[3] ; /* ...add only "*.*" */
|
|
}
|
|
|
|
//
|
|
// If was a drive then don't put wild card stuff on end or
|
|
// dir c: will be the same as dir c:\*
|
|
// Otherwise append wild card spec.
|
|
//
|
|
if (!IsDriveNameOnly(cis->fspec)) {
|
|
cis->fspec = mystrcpy(gmkstr((cbPath+5)*sizeof(TCHAR)), cis->fspec) ;
|
|
mystrcat(cis->fspec, sds) ;
|
|
}
|
|
|
|
cis->buf->dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY ; /* Fixup attribute */
|
|
DEBUG((CTGRP, SFLVL, "SCANFSPEC: changed fspec to fspec = `%ws'",cis->fspec)) ;
|
|
}
|
|
|
|
|
|
/* Get a pointer to the end of the path in fspec. Everytime a PathChar or
|
|
* a correctly placed COLON is found, the pointer is updated. "." and ".."
|
|
* are not looked for because they should be caught above.
|
|
*/
|
|
|
|
for (cbPath=1,wptr=NULL,fspec=cis->fspec; c=*fspec; fspec++,cbPath++) {
|
|
if (c == PathChar || (c == COLON && cbPath == 2)) {
|
|
wptr = fspec ;
|
|
}
|
|
}
|
|
|
|
cis->pathend = wptr ;
|
|
|
|
if (wptr) { /* Load ptr to fspec's filename */
|
|
cis->fnptr = (*wptr) ? wptr+1 : wptr ;
|
|
} else {
|
|
wptr = cis->fnptr = cis->fspec ;
|
|
}
|
|
|
|
if (mystrchr(wptr, STAR) || mystrchr(wptr, QMARK)) { /* has wildcards*/
|
|
cis->flags |= CI_NAMEWILD;
|
|
tywild = TRUE; /* global type wild */
|
|
}
|
|
cis->extptr = mystrchr(wptr, DOT); /* look for extension */
|
|
|
|
DEBUG((CTGRP, SFLVL,
|
|
"SCANFSPEC: pathend = %04x fnptr = %04x extptr = %04x flags = %04x",
|
|
cis->pathend, cis->fnptr, cis->extptr, cis->flags)) ;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
|
|
/*** SetFsSetSaveDir - save current directory and change to another one
|
|
*
|
|
* Purpose:
|
|
* Parse fspec.
|
|
* Save the current directory and change to the new directory
|
|
* specified in fspec.
|
|
*
|
|
* PCPYINFO SetFsSetSaveDir(TCHAR *fspec)
|
|
*
|
|
* Args:
|
|
* fspec - the filespec to use
|
|
*
|
|
* Returns:
|
|
* A ptr to the cpyinfo struct fsinfo.
|
|
* FAILURE otherwise.
|
|
* SaveDir will contain what default dir was when SetFsSetSaveDir was
|
|
* called.
|
|
* CurDrvDir will contain the directory to execute the command in.
|
|
*
|
|
* *** W A R N I N G ! ***
|
|
* THIS ROUTINE WILL CAUSE AN ABORT IF MEMORY CANNOT BE ALLOCATED
|
|
* THIS ROUTINE MUST NOT BE CALLED DURING A SIGNAL
|
|
* CRITICAL SECTION OR DURING RECOVERY FROM AN ABORT
|
|
*
|
|
*/
|
|
|
|
PCPYINFO SetFsSetSaveDir(fspec)
|
|
TCHAR *fspec ;
|
|
{
|
|
TCHAR *tmpptr;
|
|
TCHAR *buftemp;
|
|
TCHAR buft[MAX_PATH];
|
|
|
|
TCHAR *pathend ; /* Ptr to the end of the path in fspec */
|
|
TCHAR c ; /* Work variable */
|
|
PCPYINFO fsinfo ;/* Filespec information struct */
|
|
unsigned attr; /* work variable */
|
|
PWIN32_FIND_DATA pfdSave;
|
|
|
|
|
|
fsinfo = (PCPYINFO)gmkstr(sizeof(CPYINFO)) ; /*WARNING*/
|
|
|
|
fsinfo->fspec = fspec ;
|
|
|
|
ScanFSpec(fsinfo) ;
|
|
|
|
pfdSave = fsinfo->buf; /* save original find buffer */
|
|
fspec = fsinfo->fspec ;
|
|
pathend = fsinfo->pathend ;
|
|
DEBUG((CTGRP, SSLVL, "SFSSD: pathend = `%ws' fnptr = `%ws'",
|
|
fsinfo->pathend, fsinfo->fnptr)) ;
|
|
|
|
SaveDir = gmkstr(MAX_PATH*sizeof(TCHAR)) ; /*WARNING*/
|
|
GetDir(SaveDir, GD_DEFAULT); /* SaveDir will be current default */
|
|
DEBUG((CTGRP, SSLVL, "SFSSD: SaveDir = `%ws'", SaveDir)) ;
|
|
|
|
/* Added new test to second conditional below to test for the byte
|
|
* preceeding pathend to also be a PathChar. In this way, "\\"
|
|
* in the root position will case a ChangeDir() call on "\\" which
|
|
* will fail and cause an invalid directory error as do similar
|
|
* sequences in other positions in the filespec.
|
|
*/
|
|
if (FullPath(buft,fspec,MAX_PATH))
|
|
{
|
|
return((PCPYINFO) FAILURE) ;
|
|
}
|
|
|
|
buftemp = mystrrchr(buft,PathChar) + 1;
|
|
|
|
*buftemp = NULLC;
|
|
|
|
mystrcpy(CurDrvDir,buft);
|
|
|
|
if (pathend && *pathend != COLON) {
|
|
if (*pathend == PathChar &&
|
|
(pathend == fspec ||
|
|
*(tmpptr = prevc(fspec, pathend)) == COLON ||
|
|
*tmpptr == PathChar)) {
|
|
pathend++ ;
|
|
}
|
|
c = *pathend;
|
|
*pathend = NULLC;
|
|
DEBUG((CTGRP, SSLVL, "SFSSD: path = `%ws'", fspec)) ;
|
|
attr = GetFileAttributes(fspec);
|
|
DosErr = (attr != -1 ? NO_ERROR : GetLastError());
|
|
*pathend = c;
|
|
if (DosErr) {
|
|
return((PCPYINFO) FAILURE) ;
|
|
}
|
|
}
|
|
|
|
ScanFSpec(fsinfo) ; /* re-scan in case quotes disappeared */
|
|
fsinfo->buf = pfdSave; /* reset original find buffer */
|
|
/* the original is not freed, because */
|
|
/* it will be freed by command cleanup */
|
|
return(fsinfo) ;
|
|
}
|