/*++ 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 }