windows-nt/Source/XPSP1/NT/base/cmd/cpath.c
2020-09-26 16:20:57 +08:00

663 lines
18 KiB
C

/*++
Copyright (c) 1988-1999 Microsoft Corporation
Module Name:
cpath.c
Abstract:
Path-related commands
--*/
#include "cmd.h"
extern TCHAR SwitChar, PathChar;
extern TCHAR Fmt17[] ;
extern TCHAR CurDrvDir[] ;
extern int LastRetCode ; /* @@ */
extern TCHAR TmpBuf[] ;
/**************** START OF SPECIFICATIONS ***********************/
/* */
/* SUBROUTINE NAME: eMkDir */
/* */
/* DESCRIPTIVE NAME: Begin execution of the MKDIR command */
/* */
/* FUNCTION: This routine will make any number of directories, */
/* and will continue if it encounters a bad argument. */
/* eMkDir will be called if the user enters MD or */
/* MKDIR on the command line. */
/* */
/* NOTES: */
/* */
/* ENTRY POINT: eMkDir */
/* LINKAGE: Near */
/* */
/* INPUT: n - parse tree node containing the MKDIR command */
/* */
/* EXIT-NORMAL: returns SUCCESS if all directories were */
/* successfully created. */
/* */
/* EXIT-ERROR: returns FAILURE otherwise */
/* */
/* EFFECTS: None. */
/* */
/* INTERNAL REFERENCES: */
/* ROUTINES: */
/* LoopThroughArgs - break up command line, call MdWork */
/* */
/* EXTERNAL REFERENCES: */
/* ROUTINES: */
/* */
/**************** END OF SPECIFICATIONS *************************/
int eMkdir(n)
struct cmdnode *n ;
{
DEBUG((PCGRP, MDLVL, "MKDIR: Entered.")) ;
return(LastRetCode = LoopThroughArgs(n->argptr, MdWork, LTA_CONT)) ;
}
/**************** START OF SPECIFICATIONS ***********************/
/* */
/* SUBROUTINE NAME: MdWork */
/* */
/* DESCRIPTIVE NAME: Make a directory */
/* */
/* FUNCTION: MdWork creates a new directory. */
/* */
/* NOTES: */
/* */
/* ENTRY POINT: MdWork */
/* LINKAGE: Near */
/* */
/* INPUT: arg - a pointer to a NULL terminated string of the */
/* new directory to create. */
/* */
/* EXIT-NORMAL: returns SUCCESS if the directory is made */
/* successfully */
/* */
/* EXIT-ERROR: returns FAILURE otherwise */
/* */
/* EFFECTS: None. */
/* */
/* INTERNAL REFERENCES: */
/* ROUTINES: */
/* PutStdErr - Writes to standard error */
/* */
/* EXTERNAL REFERENCES: */
/* ROUTINES: */
/* DOSMKDIR */
/* */
/**************** END OF SPECIFICATIONS *************************/
int MdWork(arg)
TCHAR *arg ;
{
ULONG Status;
TCHAR *lpw;
TCHAR TempBuffer[MAX_PATH];
DWORD Length;
/* Check if drive is valid because Dosmkdir does not
return invalid drive @@5 */
if ((arg[1] == COLON) && !IsValidDrv(*arg)) {
PutStdErr(ERROR_INVALID_DRIVE, NOARGS);
return(FAILURE) ;
}
Length = GetFullPathName(arg, MAX_PATH, TempBuffer, &lpw);
if (Length == 0) {
PutStdErr( GetLastError(), NOARGS);
return FAILURE;
}
if (Length >= MAX_PATH) {
PutStdErr( MSG_FULL_PATH_TOO_LONG, ONEARG, arg );
return FAILURE;
}
if (CreateDirectory( arg, NULL )) {
return SUCCESS;
}
Status = GetLastError();
if (Status == ERROR_ALREADY_EXISTS) {
PutStdErr( MSG_DIR_EXISTS, ONEARG, arg );
return FAILURE;
} else if (Status != ERROR_PATH_NOT_FOUND) {
PutStdErr( Status, NOARGS);
return FAILURE;
}
//
// If no extensions, then simply fail.
//
if (!fEnableExtensions) {
PutStdErr(ERROR_CANNOT_MAKE, NOARGS);
return FAILURE;
}
//
// loop over input path and create any needed intermediary directories.
//
// Find the point in the string to begin the creation. Note, for UNC
// names, we must skip the machine and the share
//
if (TempBuffer[1] == COLON) {
//
// Skip D:\
//
lpw = TempBuffer+3;
} else if (TempBuffer[0] == BSLASH && TempBuffer[1] == BSLASH) {
//
// Skip \\server\share\
//
lpw = TempBuffer+2;
while (*lpw && *lpw != BSLASH) {
lpw++;
}
if (*lpw) {
lpw++;
}
while (*lpw && *lpw != BSLASH) {
lpw++;
}
if (*lpw) {
lpw++;
}
} else {
//
// For some reason, GetFullPath has given us something we can't understand
//
PutStdErr(ERROR_CANNOT_MAKE, NOARGS);
return FAILURE;
}
//
// Walk through the components creating them
//
while (*lpw) {
//
// Move forward until the next path separator
//
while (*lpw && *lpw != BSLASH) {
lpw++;
}
//
// If we've encountered a path character, then attempt to
// make the given path.
//
if (*lpw == BSLASH) {
*lpw = NULLC;
if (!CreateDirectory( TempBuffer, NULL )) {
Status = GetLastError();
if (Status != ERROR_ALREADY_EXISTS) {
PutStdErr( ERROR_CANNOT_MAKE, NOARGS );
return FAILURE;
}
}
*lpw++ = BSLASH;
}
}
if (!CreateDirectory( TempBuffer, NULL )) {
Status = GetLastError( );
if (Status != ERROR_ALREADY_EXISTS) {
PutStdErr( Status, NOARGS);
return FAILURE;
}
}
return(SUCCESS);
}
/*** eChdir - execute the Chdir command
*
* Purpose:
* If the command is "cd", display the current directory of the current
* drive.
*
* If the command is "cd d:", display the current directory of drive d.
*
* If the command is "cd str", change the current directory to str.
*
* int eChdir(struct cmdnode *n)
*
* Args:
* n - the parse tree node containing the chdir command
*
* Returns:
* SUCCESS if the requested task was accomplished.
* FAILURE if it was not.
*
*/
int eChdir(n)
struct cmdnode *n ;
{
TCHAR *tas, *src, *dst; /* Tokenized arg string */
TCHAR dirstr[MAX_PATH] ;/* Holds current dir of specified drive */
//
// If extensions are enabled, dont treat spaces as delimeters so it is
// easier to CHDIR to directory names with embedded spaces without having
// to quote the directory name
//
tas = TokStr(n->argptr, TEXT( "" ), fEnableExtensions ? TS_WSPACE|TS_SDTOKENS : TS_SDTOKENS) ;
if (fEnableExtensions) {
//
// If extensions were enabled we could have some trailing spaces
// that need to be nuked since there weren't treated as delimeters
// by TokStr call above.
//
// We compress the extra spaces out since we rely on the tokenized
// format later inside ChdirWork
//
src = tas;
dst = tas;
while (*src) {
while (*dst = *src++)
dst += 1;
while (_istspace(dst[-1]))
dst -= 1;
*dst++ = NULLC;
}
*dst = NULLC;
}
DEBUG((PCGRP, CDLVL, "CHDIR: tas = `%ws'", tas)) ;
mystrcpy( tas, StripQuotes( tas ) );
//
// No arguments means display current drive and directory
//
if (*tas == NULLC) {
GetDir(CurDrvDir, GD_DEFAULT) ;
cmd_printf(Fmt17, CurDrvDir) ;
} else
//
// single drive letter means display current dirctory on that drive
//
if (mystrlen(tas) == 2 && *(tas+1) == COLON && _istalpha(*tas)) {
GetDir(dirstr, *tas) ;
cmd_printf(Fmt17, dirstr) ;
} else
//
// We need to change current directory (and possibly drive)
//
{
return( LastRetCode = ChdirWork(tas) );
}
return( LastRetCode = SUCCESS );
}
int ChdirWork( TCHAR *tas )
{
unsigned i = MSG_BAD_SYNTAX;
//
// If there's no leading "/D", just chdir
// to the input path
//
if (_tcsnicmp( tas, TEXT( "/D" ), 2)) {
i = ChangeDir((TCHAR *)tas);
} else {
//
// Advance over the "/D" and intervening whitespace
//
tas = SkipWhiteSpace( tas + 2 );
//
// if there's no other switch char, strip any quotes and do
// the chdir
//
if (*tas != SwitChar) {
_tcscpy( tas, StripQuotes( tas ));
i = ChangeDir2(tas, TRUE);
}
}
if (i != SUCCESS) {
PutStdErr( i, ONEARG, tas);
return (FAILURE) ;
}
return (SUCCESS) ;
}
#define SIZEOFSTACK 25
typedef struct {
PTCHAR SavedDirectory;
TCHAR NetDriveCreated;
} *PSAVEDDIRECTORY;
PSAVEDDIRECTORY SavedDirectoryStack = NULL;
int StrStackDepth = 0;
int MaxStackDepth = 0;
int GetDirStackDepth(void)
{
return StrStackDepth;
}
int
PushStr ( PTCHAR pszString )
{
//
// If we're full, grow the stack by an increment
//
if (StrStackDepth == MaxStackDepth) {
PSAVEDDIRECTORY Tmp =
realloc( SavedDirectoryStack,
sizeof( *SavedDirectoryStack ) * (MaxStackDepth + SIZEOFSTACK));
if (Tmp == NULL) {
return FALSE;
}
SavedDirectoryStack = Tmp;
MaxStackDepth += SIZEOFSTACK;
}
SavedDirectoryStack[ StrStackDepth ].SavedDirectory = pszString;
SavedDirectoryStack[ StrStackDepth ].NetDriveCreated = NULLC;
StrStackDepth += 1;
return TRUE;
}
PTCHAR
PopStr ()
{
PTCHAR pszString;
if (StrStackDepth == 0) {
return ( NULL );
}
StrStackDepth -= 1;
pszString = SavedDirectoryStack[StrStackDepth].SavedDirectory;
if (SavedDirectoryStack[StrStackDepth].NetDriveCreated != NULLC) {
TCHAR szLocalName[4];
szLocalName[0] = SavedDirectoryStack[StrStackDepth].NetDriveCreated;
szLocalName[1] = COLON;
szLocalName[2] = NULLC;
SavedDirectoryStack[StrStackDepth].NetDriveCreated = NULLC;
try {
WNetCancelConnection2(szLocalName, 0, TRUE);
} except (EXCEPTION_EXECUTE_HANDLER) {
}
}
SavedDirectoryStack[StrStackDepth].SavedDirectory = NULL;
//
// If we can eliminate an increment from the stack, go do so
//
if (StrStackDepth > 0 && StrStackDepth + 2 * SIZEOFSTACK <= MaxStackDepth) {
PSAVEDDIRECTORY Tmp =
realloc( SavedDirectoryStack,
sizeof( *SavedDirectoryStack ) * (StrStackDepth + SIZEOFSTACK));
if (Tmp != NULL) {
SavedDirectoryStack = Tmp;
MaxStackDepth = StrStackDepth + SIZEOFSTACK;
}
}
return ( pszString );
}
VOID
DumpStrStack() {
int i;
for (i=StrStackDepth-1; i>=0; i--) {
cmd_printf( Fmt17, SavedDirectoryStack[i].SavedDirectory );
}
return;
}
BOOLEAN
PushCurDir()
{
PTCHAR pszCurDir;
GetDir( CurDrvDir, GD_DEFAULT ) ;
if ((pszCurDir=HeapAlloc( GetProcessHeap( ), 0, (mystrlen( CurDrvDir )+1)*sizeof( TCHAR ))) != NULL) {
mystrcpy( pszCurDir, CurDrvDir) ;
if (PushStr( pszCurDir ))
return ( TRUE );
HeapFree( GetProcessHeap( ), 0, pszCurDir );
}
return ( FALSE );
}
int ePushDir(n)
struct cmdnode *n ;
{
TCHAR *tas ; /* Tokenized arg string */
PTCHAR pszTmp, s;
//
// If extensions are enabled, dont treat spaces as delimeters so it is
// easier to CHDIR to directory names with embedded spaces without having
// to quote the directory name
//
tas = TokStr(n->argptr, NULL, fEnableExtensions ? TS_WSPACE|TS_NOFLAGS : TS_NOFLAGS) ;
if (fEnableExtensions) {
//
// If extensions were enabled we could have some trailing spaces
// that need to be nuked since there weren't treated as delimeters
// by TokStr call above.
//
s = lastc(tas);
while (s > tas) {
if (_istspace(*s))
*s-- = NULLC;
else
break;
}
}
mystrcpy(tas, StripQuotes(tas) );
LastRetCode = SUCCESS;
if (*tas == NULLC) {
//
// Print out entire stack
//
DumpStrStack();
} else if (PushCurDir()) {
//
// If extensions are enabled and a UNC name was given, then do
// a temporary NET USE to define a drive letter that we can
// use to change drive/directory to. The matching POPD will
// delete the temporary drive letter.
//
if (fEnableExtensions && tas[0] == BSLASH && tas[1] == BSLASH) {
NETRESOURCE netResource;
TCHAR szLocalName[4];
PTCHAR s;
//
// If there is a directory specified after the \\server\share
// then test to see if that directory exists before doing any
// network connections
//
if ((s = _tcschr(&tas[2], BSLASH)) != NULL
&& (s = _tcschr(s+1, BSLASH)) != NULL) {
if (GetFileAttributes( tas ) == -1) {
LastRetCode = GetLastError( );
if (LastRetCode == ERROR_FILE_NOT_FOUND) {
LastRetCode = ERROR_PATH_NOT_FOUND;
}
} else {
*s++ = NULLC;
}
}
szLocalName[0] = TEXT('Z');
szLocalName[1] = COLON;
szLocalName[2] = NULLC;
netResource.dwType = RESOURCETYPE_DISK;
netResource.lpLocalName = szLocalName;
netResource.lpRemoteName = tas;
netResource.lpProvider = NULL;
while (LastRetCode == NO_ERROR && szLocalName[0] != TEXT('A')) {
try {
LastRetCode = WNetAddConnection2( &netResource, NULL, NULL, 0);
} except (LastRetCode = GetExceptionCode( ), EXCEPTION_EXECUTE_HANDLER) {
}
switch (LastRetCode) {
case NO_ERROR:
SavedDirectoryStack[StrStackDepth-1].NetDriveCreated = szLocalName[0];
tas[0] = szLocalName[0];
tas[1] = szLocalName[1];
tas[2] = BSLASH;
if (s != NULL)
_tcscpy(&tas[3], s);
else
tas[3] = NULLC;
goto godrive;
case ERROR_ALREADY_ASSIGNED:
case ERROR_DEVICE_ALREADY_REMEMBERED:
szLocalName[0] = (TCHAR)((UCHAR)szLocalName[0] - 1);
LastRetCode = NO_ERROR;
break;
default:
break;
}
}
godrive: ;
}
//
// The NET USE succeeded, now attempt to change the directory
// as well.
//
if (LastRetCode == NO_ERROR
&& (LastRetCode = ChangeDir2( tas, TRUE )) == SUCCESS) {
if (tas[1] == ':') {
GetDir(CurDrvDir,tas[0]);
}
}
if (LastRetCode != SUCCESS) {
pszTmp = PopStr();
HeapFree(GetProcessHeap(), 0, pszTmp);
PutStdErr( LastRetCode, NOARGS );
LastRetCode = FAILURE;
}
} else {
PutStdErr( MSG_ERROR_PUSHD_DEPTH_EXCEEDED, NOARGS );
LastRetCode = FAILURE;
}
return ( LastRetCode );
}
int ePopDir(n)
struct cmdnode *n ;
{
PTCHAR pszCurDir;
UNREFERENCED_PARAMETER( n );
if (pszCurDir = PopStr()) {
if (ChangeDir2( pszCurDir,TRUE ) == SUCCESS) {
HeapFree(GetProcessHeap(), 0, pszCurDir);
return( SUCCESS );
}
HeapFree(GetProcessHeap(), 0, pszCurDir);
}
return( FAILURE );
}
/*** eRmdir - begin the execution of the Rmdir command
*
* Purpose:
* To remove an arbitrary number of directories.
*
* int eRmdir(struct cmdnode *n)
*
* Args:
* n - the parse tree node containing the rmdir command
*
* Returns:
* SUCCESS if all directories were removed.
* FAILURE if they weren't.
*
*/
int eRmdir(n)
struct cmdnode *n ;
{
DEBUG((PCGRP, RDLVL, "RMDIR: Entered.")) ;
return(RdWork(n->argptr)); // in del.c
}