1192 lines
43 KiB
C
1192 lines
43 KiB
C
/*++
|
|
|
|
Copyright (c) 1988-1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
cfile.c
|
|
|
|
Abstract:
|
|
|
|
File manipulation support
|
|
|
|
--*/
|
|
|
|
#include "cmd.h"
|
|
|
|
#define Wild(spec) ((spec)->flags & (CI_NAMEWILD))
|
|
|
|
extern int LastRetCode ;
|
|
extern jmp_buf CmdJBuf2 ;
|
|
|
|
extern TCHAR Fmt19[], Fmt17[];
|
|
extern TCHAR CurDrvDir[] ;
|
|
|
|
extern TCHAR YesChar, NoChar ;
|
|
|
|
extern TCHAR *SaveDir ;
|
|
|
|
extern TCHAR PathChar, TmpBuf[], SwitChar;
|
|
|
|
extern unsigned DosErr ;
|
|
extern unsigned flgwd ; /* M021 */
|
|
|
|
extern int LastRetCode ;
|
|
|
|
extern BOOL CtrlCSeen;
|
|
extern PTCHAR pszTitleCur;
|
|
extern BOOLEAN fTitleChanged;
|
|
|
|
//
|
|
// Internal prototypes
|
|
//
|
|
PCPYINFOSetFsSetSaveDir() ;
|
|
|
|
/*** ErrorDisplayAndJumnp - handle errors
|
|
*
|
|
* Purpose:
|
|
* eRename and eMove error handler. Returns to routine via longjmp
|
|
*
|
|
* ErrorDisplayAndJump(unsigned int errmsg)
|
|
*
|
|
*
|
|
* Args:
|
|
* errmsg - the error message to print
|
|
*
|
|
*/
|
|
|
|
void ErrorDisplayAndJump( unsigned int errmsg )
|
|
{
|
|
|
|
PutStdErr( errmsg, NOARGS );
|
|
|
|
RestoreSavedDirectory( );
|
|
|
|
longjmp( CmdJBuf2, 1 ) ;
|
|
}
|
|
|
|
|
|
/*
|
|
** This routine returns the longest pathlength possible from the input path
|
|
** It assumes that the input path is a buffer that it can extend by a
|
|
** wildcard '\*' to search the file, if it is a directory.
|
|
** The input path must be fully qualified, eg: "c:\winnt\system32\kernel32.dll"
|
|
**
|
|
** Input:
|
|
** pPath fully qualified Pathname
|
|
** pCch pointer to length of pathname
|
|
** Returns:
|
|
** TRUE succeeded, pCch contains length
|
|
** FALSE error occurred
|
|
*/
|
|
BOOL
|
|
GreatestLength(
|
|
TCHAR *pPath,
|
|
int *pCch
|
|
)
|
|
{
|
|
WIN32_FIND_DATA fd;
|
|
HANDLE hFind;
|
|
DWORD err;
|
|
int cch;
|
|
int cchThis;
|
|
DWORD attr;
|
|
TCHAR *pLast;
|
|
BOOL MoreFiles;
|
|
|
|
/* assume a file, or empty directory */
|
|
*pCch = cch = _tcslen(pPath) - 2; /* _tcslen(TEXT("C:")) */
|
|
|
|
if ((attr=GetFileAttributes(pPath)) == 0xffffffff) {
|
|
PutStdErr(GetLastError(), NOARGS);
|
|
return FALSE;
|
|
}
|
|
if ( !(attr & FILE_ATTRIBUTE_DIRECTORY)) { /* if just a file... */
|
|
return TRUE;
|
|
}
|
|
|
|
/* path is a directory, search it ... */
|
|
|
|
pLast = pPath + _tcslen(pPath);
|
|
if (*(pLast-1) == BSLASH) {
|
|
*pLast = STAR;
|
|
*(pLast+1) = NULLC;
|
|
} else {
|
|
*pLast = BSLASH;
|
|
*(pLast+1) = STAR;
|
|
*(pLast+2) = NULLC;
|
|
}
|
|
|
|
if ((hFind=FindFirstFile(pPath, &fd)) == INVALID_HANDLE_VALUE) {
|
|
//
|
|
// Check that failure was not due to some system error such
|
|
// as an abort on access to floppy
|
|
//
|
|
err = GetLastError();
|
|
FindClose(hFind);
|
|
if (err != ERROR_FILE_NOT_FOUND && err != ERROR_NO_MORE_FILES) {
|
|
PutStdErr(err, NOARGS);
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
MoreFiles = TRUE;
|
|
do {
|
|
if (!_tcscmp(fd.cFileName, TEXT(".")))
|
|
continue;
|
|
if (!_tcscmp(fd.cFileName, TEXT("..")))
|
|
continue;
|
|
if (_tcslen( fd.cFileName ) == 0) {
|
|
continue;
|
|
}
|
|
|
|
if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
|
|
TCHAR path[MAX_PATH];
|
|
|
|
_tcscpy(path, pPath);
|
|
*(path+_tcslen(path)-1) = NULLC; /* zap asterisk */
|
|
_tcscat(path, fd.cFileName);
|
|
if (!GreatestLength(path, &cchThis))
|
|
break;
|
|
|
|
*pCch = max(*pCch, cch + cchThis);
|
|
} else {
|
|
*pCch = max(*pCch, (int) _tcslen(fd.cFileName));
|
|
}
|
|
|
|
} while ( MoreFiles = FindNextFile(hFind, &fd) );
|
|
|
|
err = GetLastError();
|
|
FindClose(hFind);
|
|
|
|
if ( MoreFiles ) {
|
|
return FALSE;
|
|
} else if ( err != ERROR_NO_MORE_FILES ) {
|
|
PutStdErr(err, NOARGS);
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void
|
|
RestoreSavedDirectory( void )
|
|
{
|
|
if (SaveDir) {
|
|
mystrcpy( CurDrvDir, SaveDir );
|
|
SaveDir = NULL;
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
GetPromptOkay(
|
|
const TCHAR *arg,
|
|
BOOL *promptokay
|
|
|
|
)
|
|
{
|
|
BOOL Result;
|
|
const TCHAR *p, *p1;
|
|
|
|
Result = TRUE;
|
|
if (arg != NULL) {
|
|
p = arg;
|
|
while (*p && *p <= SPACE)
|
|
p += 1;
|
|
p1 = p;
|
|
while (*p1 && *p1 > SPACE)
|
|
p1 += 1;
|
|
if (!_tcsnicmp(p, TEXT("/Y"),(UINT)(p1-p)))
|
|
*promptokay = FALSE;
|
|
else
|
|
if (!_tcsnicmp(p, TEXT("/-Y"),(UINT)(p1-p)))
|
|
*promptokay = TRUE;
|
|
else
|
|
Result = FALSE;
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
int eCopy(n)
|
|
struct cmdnode *n ;
|
|
{
|
|
return(LastRetCode = copy(n->argptr)) ;
|
|
}
|
|
|
|
|
|
int eDelete(n)
|
|
struct cmdnode *n ;
|
|
{
|
|
int DelWork() ;
|
|
|
|
return(LastRetCode = DelWork(n->argptr));
|
|
}
|
|
|
|
|
|
/********************* START OF SPECIFICATION **************************/
|
|
/* */
|
|
/* SUBROUTINE NAME: eRename */
|
|
/* */
|
|
/* DESCRIPTIVE NAME: Rename Internal Command */
|
|
/* */
|
|
/* FUNCTION: Rename files and subdirectories. Wildcards only applies */
|
|
/* to file names. */
|
|
/* */
|
|
/* NOTES: @@5* */
|
|
/* */
|
|
/* ENTRY POINT: eRename */
|
|
/* LINKAGE: NEAR */
|
|
/* */
|
|
/* INPUT: */
|
|
/* n - the parse tree node containing the rename command */
|
|
/* */
|
|
/* OUTPUT: None. */
|
|
/* */
|
|
/* EXIT-NORMAL: */
|
|
/* Return SUCCESS to the caller. */
|
|
/* */
|
|
/* EXIT-ERROR: */
|
|
/* Return FAILURE to the caller. */
|
|
/* */
|
|
/* EFFECTS: None. */
|
|
/* */
|
|
/* INTERNAL REFERENCES: */
|
|
/* ROUTINES: */
|
|
/* RenWork - Worker routine for rename. */
|
|
/* */
|
|
/* EXTERNAL REFERENCES: */
|
|
/* ROUTINES: */
|
|
/* None */
|
|
/* */
|
|
/********************** END OF SPECIFICATION **************************/
|
|
|
|
int eRename(n)
|
|
struct cmdnode *n ;
|
|
{
|
|
int RenWork(); /* @@ */
|
|
|
|
return(LastRetCode = RenWork( n )); /* @@ */
|
|
}
|
|
|
|
|
|
/********************* START OF SPECIFICATION **************************/
|
|
/* */
|
|
/* SUBROUTINE NAME: RenWork */
|
|
/* */
|
|
/* DESCRIPTIVE NAME: Rename Internal Command Worker */
|
|
/* */
|
|
/* FUNCTION: Rename files and subdirectories. Wildcards only applies */
|
|
/* to file names. */
|
|
/* */
|
|
/* NOTES: @@5* */
|
|
/* */
|
|
/* ENTRY POINT: RenWork */
|
|
/* LINKAGE: NEAR */
|
|
/* */
|
|
/* INPUT: */
|
|
/* n - The parse tree node containing the rename command */
|
|
/* */
|
|
/* OUTPUT: None. */
|
|
/* */
|
|
/* EXIT-NORMAL: */
|
|
/* Return SUCCESS to the caller. */
|
|
/* */
|
|
/* EXIT-ERROR: */
|
|
/* Return FAILURE to the caller. */
|
|
/* */
|
|
/* EFFECTS: None. */
|
|
/* */
|
|
/* INTERNAL REFERENCES: */
|
|
/* ROUTINES: */
|
|
/* ffirst - Find the first matching specified file. */
|
|
/* fnext - Find the next matching specified file handle*/
|
|
/* findclose - Close the file with the specified file handle, */
|
|
/* hnFirst which is given by ffirst or fnext. */
|
|
/* TokStr - Tokenize argument strings. */
|
|
/* wildcard_rename - Obtain name based on wildcard specification.*/
|
|
/* SetFsSetSaveDir - Save the current directory. */
|
|
/* GetDir - Get the specified directory. */
|
|
/* ChangeDir - Change to the specified directory. */
|
|
/* PutStdErr - Displays an error message. */
|
|
/* Wild - check if the arg contains wild card. */
|
|
/* */
|
|
/* EXTERNAL REFERENCES: */
|
|
/* ROUTINES: */
|
|
/* None */
|
|
/* DOSMOVE - Rename file and directory names. */
|
|
/* DOSCASEMAP - Change lower case character to upper case. */
|
|
/* DOSFILEMODE - Get attribute of specified file. */
|
|
/* */
|
|
/********************** END OF SPECIFICATION **************************/
|
|
|
|
int RenWork(n) /* @@ */
|
|
struct cmdnode *n ;
|
|
{
|
|
TCHAR *arg1 ; /* Ptr to 1st arg */
|
|
TCHAR *arg2 ; /* Ptr to 2nd arg */
|
|
PCPYINFO a1info ; /* Holds arg1 fspec info */
|
|
PCPYINFO SetFsSetSaveDir();
|
|
TCHAR Source[MAX_PATH];
|
|
TCHAR bufdst[MAX_PATH]; /* path of destination file*/
|
|
TCHAR Replacement[MAX_PATH];
|
|
int wlen; /* length of source path */
|
|
int rc; /* return code */
|
|
HANDLE hnFirst ; /* Findfirst handle */
|
|
unsigned attr ;
|
|
unsigned i; /* Temp Return Code */
|
|
TCHAR *j ; /* Temp Ptr to dir name */
|
|
unsigned wild_flag ; /* wildcard flag */
|
|
TCHAR pcstr[3] ;
|
|
unsigned retval = SUCCESS;
|
|
|
|
DEBUG((FCGRP, RELVL, "RENAME: arptr = `%ws'", n->argptr)) ;
|
|
|
|
if (setjmp(CmdJBuf2))
|
|
return(FAILURE) ;
|
|
|
|
/* There should be only two arguments */
|
|
if (!*(arg1 = TokStr(n->argptr, NULL, TS_NOFLAGS)) ||
|
|
!*(arg2 = arg1 + mystrlen(arg1) + 1) ||
|
|
*(arg2 + mystrlen(arg2) +1)) { /* @@5g */
|
|
|
|
ErrorDisplayAndJump( MSG_BAD_SYNTAX );
|
|
}
|
|
|
|
mystrcpy( arg1, StripQuotes(arg1) ); /* 509 */
|
|
mystrcpy( arg2, StripQuotes(arg2) ); /* 509 */
|
|
|
|
if ((a1info = SetFsSetSaveDir(arg1)) == (PCPYINFO)FAILURE) {
|
|
ErrorDisplayAndJump( DosErr );
|
|
}
|
|
|
|
mystrcpy( Source, CurDrvDir );
|
|
|
|
mystrcpy(bufdst,CurDrvDir); /* save path of dest */
|
|
|
|
wlen = mystrlen( Source ); /* get len of src path */
|
|
|
|
if ( (a1info->buf->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0 ) {
|
|
mystrcpy(&Source[wlen],a1info->fnptr);
|
|
} else {
|
|
Source[--wlen] = NULLC ;
|
|
bufdst[wlen] = NULLC ;
|
|
}
|
|
|
|
/* if not wild since */
|
|
if (!Wild(a1info)) {
|
|
a1info->buf->dwFileAttributes =
|
|
GetFileAttributes( StripQuotes(Source) );
|
|
|
|
if (a1info->buf->dwFileAttributes == -1 ) {
|
|
ErrorDisplayAndJump( GetLastError( )) ;
|
|
}
|
|
}
|
|
|
|
|
|
if (*(arg2+1) == COLON ||
|
|
mystrchr(arg2,PathChar)) {
|
|
ErrorDisplayAndJump( MSG_BAD_SYNTAX );
|
|
}
|
|
|
|
/**********************************************/
|
|
/* M009 - Always specifiy drive, filename, */
|
|
/* and extension. Note, it is */
|
|
/* assumed that SaveDir always starts */
|
|
/* with a drive letter */
|
|
/**********************************************/
|
|
|
|
Replacement[0] = CurDrvDir[0] ; /* @@5h */
|
|
Replacement[1] = COLON ;
|
|
|
|
|
|
/**********************************************/
|
|
/* Set flag whether arg1 contains */
|
|
/* wildcard or not. */
|
|
/**********************************************/
|
|
|
|
pcstr[0] = STAR ;
|
|
pcstr[1] = QMARK ;
|
|
pcstr[2] = NULLC ;
|
|
wild_flag = ((mystrcspn(arg1,pcstr)) < mystrlen(arg1)) ;
|
|
|
|
/**********************************************/
|
|
/* Issue ffirst for a file name */
|
|
/**********************************************/
|
|
if ( !ffirst(Source, attr = FILE_ATTRIBUTE_ARCHIVE, a1info->buf, &hnFirst )) {
|
|
|
|
/*********************************************/
|
|
/* Issue ffirst for a directory name */
|
|
/*********************************************/
|
|
if (!ffirst(Source, attr = FILE_ATTRIBUTE_DIRECTORY, a1info->buf, &hnFirst )) {
|
|
if (DosErr == ERROR_NO_MORE_FILES) {
|
|
DosErr = ERROR_FILE_NOT_FOUND;
|
|
}
|
|
ErrorDisplayAndJump( DosErr );
|
|
} else {
|
|
|
|
if (wild_flag) {
|
|
findclose( hnFirst );
|
|
ErrorDisplayAndJump( MSG_BAD_SYNTAX );
|
|
}
|
|
}
|
|
}
|
|
|
|
Source[wlen] = NULLC; /* make filename = NULL */
|
|
|
|
rc = 0 ; /* @@5 */
|
|
|
|
do {
|
|
|
|
if (CtrlCSeen) {
|
|
findclose(hnFirst) ;
|
|
RestoreSavedDirectory( );
|
|
|
|
return(FAILURE);
|
|
}
|
|
|
|
/**********************************************/
|
|
/* if the file attribute of Source is */
|
|
/* directory then concatenate arg2 after the */
|
|
/* last "\" character of bufdst */
|
|
/**********************************************/
|
|
|
|
if ( a1info->buf->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) { /* @@5c*/
|
|
j = mystrrchr(bufdst,PathChar) ; /* @@5 */
|
|
|
|
if ( !j ) {
|
|
ErrorDisplayAndJump( MSG_REN_INVAL_PATH_FILENAME );
|
|
}
|
|
|
|
*(++j) = NULLC;
|
|
|
|
if ( (mystrlen(arg2) + 1 + mystrlen(bufdst)) > MAX_PATH ) {
|
|
ErrorDisplayAndJump( MSG_REN_INVAL_PATH_FILENAME );
|
|
}
|
|
|
|
mystrcpy(j,arg2); /* @@5 */
|
|
|
|
bufdst[mystrlen(bufdst)] = NULLC ; /* @@5 */
|
|
} /* @@5 */
|
|
else { /* @@5 */
|
|
mystrcpy(&Source[wlen],a1info->buf->cFileName);
|
|
|
|
wildcard_rename( Replacement, arg2, &Source[wlen], MAX_PATH );
|
|
|
|
if ( (wlen + 1 + mystrlen( Replacement )) > MAX_PATH ) {
|
|
ErrorDisplayAndJump( MSG_REN_INVAL_PATH_FILENAME );
|
|
}
|
|
|
|
mystrcpy(&bufdst[wlen],&Replacement[0]); /*@@4 @J1*/
|
|
}
|
|
|
|
/**********************************************/
|
|
/* Rename a file or directory */
|
|
/**********************************************/
|
|
DEBUG((FCGRP, RELVL, "RENAME: src:`%ws', dst:`%ws'", Source, bufdst)) ;
|
|
if ( !MoveFile( Source, bufdst ) ) {
|
|
/**********************************************/
|
|
/* rename fails */
|
|
/**********************************************/
|
|
|
|
i = GetLastError();
|
|
if (i == ERROR_ALREADY_EXISTS) {
|
|
i = MSG_DUP_FILENAME_OR_NOT_FD;
|
|
}
|
|
|
|
rc = i ; /* @@5 Save the error code*/
|
|
PutStdErr(rc,NOARGS); /* @@5 Put our err message*/
|
|
}
|
|
|
|
} while (fnext(a1info->buf, attr, hnFirst ));
|
|
|
|
/**********************************************/
|
|
/* No more file is found */
|
|
/**********************************************/
|
|
findclose(hnFirst) ;
|
|
|
|
RestoreSavedDirectory( );
|
|
|
|
return( rc ? FAILURE : SUCCESS ); /* @@5 */
|
|
}
|
|
|
|
|
|
/********************* START OF SPECIFICATION **************************/
|
|
/* */
|
|
/* SUBROUTINE NAME: eMove */
|
|
/* */
|
|
/* DESCRIPTIVE NAME: Move Internal Command */
|
|
/* */
|
|
/* FUNCTION: Parse the parameter passed and */
|
|
/* moves one or more files from directory to another */
|
|
/* directory on the same drive. If you prefer you can give */
|
|
/* the files different names. */
|
|
/* */
|
|
/* NOTES: ( New routine for Relaese 1.2 ) @@5* */
|
|
/* */
|
|
/* ENTRY POINT: eMove */
|
|
/* LINKAGE: NEAR */
|
|
/* */
|
|
/* INPUT: */
|
|
/* n - the parse tree node containing the copy command */
|
|
/* */
|
|
/* OUTPUT: None. */
|
|
/* */
|
|
/* EXIT-NORMAL: */
|
|
/* Return SUCCESS to the caller. */
|
|
/* */
|
|
/* EXIT-ERROR: */
|
|
/* Return FAILURE to caller. */
|
|
/* */
|
|
/* EFFECTS: None. */
|
|
/* */
|
|
/* INTERNAL REFERENCES: */
|
|
/* ROUTINES: */
|
|
/* MoveParse - parse move command parameter */
|
|
/* Move - routine which actually call DosMove to move */
|
|
/* file or directory. */
|
|
/* */
|
|
/* EXTERNAL REFERENCES: */
|
|
/* ROUTINES: */
|
|
/* None */
|
|
/* */
|
|
/********************** END OF SPECIFICATION **************************/
|
|
|
|
int eMove(n)
|
|
struct cmdnode *n ;
|
|
{
|
|
unsigned i;
|
|
BOOL PromptOnOverwrite;
|
|
TCHAR arg1[MAX_PATH] ; /* Ptr to 1st arg */
|
|
TCHAR arg2[MAX_PATH] ; /* Ptr to 2nd arg */
|
|
PCPYINFO a1info ; /* Holds arg1 fspec info */
|
|
unsigned int is_dest_dir; /* generated by MoveParse(), used by Move() */
|
|
|
|
DEBUG((FCGRP, RELVL, "RENAME: arptr = `%ws'", n->argptr)) ;
|
|
|
|
if (setjmp(CmdJBuf2))
|
|
return(LastRetCode = FAILURE) ;
|
|
|
|
//
|
|
// Get default prompt okay flag from COPYCMD variable. Allow
|
|
// user to override with /Y or /-Y switch. Always assume /Y
|
|
// if command executed from inside batch script or via CMD.EXE
|
|
// command line switch (/C or /K)
|
|
//
|
|
if (SingleBatchInvocation || SingleCommandInvocation || CurrentBatchFile != 0)
|
|
PromptOnOverwrite = FALSE; // Assume /Y
|
|
else
|
|
PromptOnOverwrite = TRUE; // Assume /-Y
|
|
|
|
/* MoveParse parses the command line parameters to arg1 */
|
|
/* and arg1. In addition, a1info holds the fspec */
|
|
/* information for arg1. */
|
|
/* Based on arg1 and arg2, Move moves file(s)/directory. */
|
|
/* Move uses a1info to determine that arg1 contains */
|
|
/* wildcard. */
|
|
|
|
i = MoveParse( n,
|
|
&PromptOnOverwrite,
|
|
arg1,
|
|
arg2,
|
|
&a1info,
|
|
&is_dest_dir,
|
|
MAX_PATH,
|
|
MAX_PATH
|
|
);
|
|
if (!i) {
|
|
i = Move( arg1, arg2, PromptOnOverwrite, a1info, is_dest_dir ) ;
|
|
}
|
|
|
|
return(LastRetCode = i) ;
|
|
}
|
|
|
|
|
|
/********************* START OF SPECIFICATION **************************/
|
|
/* */
|
|
/* SUBROUTINE NAME: MoveParse */
|
|
/* */
|
|
/* DESCRIPTIVE NAME: Move Parser */
|
|
/* */
|
|
/* FUNCTION: Move Internal Function Parser */
|
|
/* */
|
|
/* NOTES: This parser breaks up the command line information */
|
|
/* into two parameters. */
|
|
/* ( New routine for Relaese 1.2 ) @@5* */
|
|
/* */
|
|
/* ENTRY POINT: MoveParse */
|
|
/* LINKAGE: NEAR */
|
|
/* */
|
|
/* INPUT: */
|
|
/* n - the parse tree node containing the move command */
|
|
/* */
|
|
/* OUTPUT: ptr1 - pointer to [drive:][path]filename to be moved from */
|
|
/* ptr2 - pointer to [path]filename to be moved to */
|
|
/* a1info - pointer to cpyinfo which has arg1 fspec info */
|
|
/* is_dest_dir - flag used by Move() */
|
|
/* */
|
|
/* EXIT-NORMAL: */
|
|
/* Return SUCCESS to the caller. */
|
|
/* */
|
|
/* EXIT-ERROR: */
|
|
/* Return FAILURE to the caller. */
|
|
/* */
|
|
/* EFFECTS: None. */
|
|
/* */
|
|
/* INTERNAL REFERENCES: */
|
|
/* ROUTINES: */
|
|
/* TokStr - Tokenize argument strings. */
|
|
/* FullPath - Figure out the full path for a file. */
|
|
/* SetFsSetSaveDir - Save current directory. */
|
|
/* */
|
|
/* EXTERNAL REFERENCES: */
|
|
/* ROUTINES: */
|
|
/* DOSQFILEMODE - Get file mode of the specified file/dir. */
|
|
/* */
|
|
/********************** END OF SPECIFICATION **************************/
|
|
int MoveParse(n, promptokay, source, target , a1info, is_dest_dir, sizpath1, sizpath2)
|
|
struct cmdnode *n ;
|
|
BOOL *promptokay ;
|
|
TCHAR *source ; /* Ptr to source file(s)/directory name */
|
|
TCHAR *target ; /* Ptr to target file(s)/directory name */
|
|
PCPYINFO* a1info ; /* Holds arg1 fspec information */
|
|
unsigned int *is_dest_dir; /* to pass to move */
|
|
unsigned sizpath1; /* size of source buffer */
|
|
unsigned sizpath2; /* size of target buffer */
|
|
|
|
{ PCPYINFO SetFsSetSaveDir() ;
|
|
TCHAR *arg1 ; /* Ptr to 1st arg */
|
|
TCHAR *arg2 ; /* Ptr to 2nd arg */
|
|
TCHAR *p1;
|
|
TCHAR *p2;
|
|
TCHAR arg22[MAX_PATH] ; /* Ptr to modified 2nd arg */
|
|
unsigned i;
|
|
unsigned concat_flag ;
|
|
unsigned att ;
|
|
/*509*/unsigned arg1len, arg2len;
|
|
|
|
//
|
|
// Get default prompt okay flag from COPYCMD variable. Allow
|
|
// user to override with first token after command.
|
|
//
|
|
GetPromptOkay(MyGetEnvVarPtr(TEXT("COPYCMD")), promptokay);
|
|
arg1 = TokStr(n->argptr, NULL, TS_NOFLAGS);
|
|
if (GetPromptOkay(arg1, promptokay))
|
|
while (*arg1++)
|
|
;
|
|
|
|
/* Get arg1. If fail to get arg1, display error message. */
|
|
if (!*arg1) {
|
|
ErrorDisplayAndJump( MSG_BAD_SYNTAX );
|
|
}
|
|
/*509*/
|
|
else if ( (arg1len = mystrlen(arg1)) > MAX_PATH) {
|
|
ErrorDisplayAndJump( MSG_REN_INVAL_PATH_FILENAME );
|
|
}
|
|
|
|
/*CurDrvDir = current directory or directory which is specified in arg1*/
|
|
/*509*/mystrcpy( arg1, StripQuotes( arg1 ) );
|
|
if (((*a1info) = SetFsSetSaveDir(arg1)) == (PCPYINFO)FAILURE) {
|
|
ErrorDisplayAndJump( DosErr );
|
|
}
|
|
/* */
|
|
/* Get arg2 out of arg1 */
|
|
|
|
arg2 = arg1 + arg1len + 1;
|
|
|
|
if ( !(*arg2) ) {
|
|
|
|
arg22[0] = SaveDir[0]; /* get current drive */
|
|
arg22[1] = COLON;
|
|
arg22[2] = NULLC;
|
|
} else if (*(arg2 + mystrlen(arg2) + 1)) { /* @@5g */
|
|
ErrorDisplayAndJump( MSG_BAD_SYNTAX );
|
|
}
|
|
/*509*/
|
|
else if ( (arg2len = mystrlen(arg2)) > MAX_PATH) {
|
|
ErrorDisplayAndJump( MSG_REN_INVAL_PATH_FILENAME );
|
|
} else {
|
|
/* If arg2 conatins a drive name, display an error message. */
|
|
|
|
/*509*/
|
|
mystrcpy
|
|
|
|
( arg2, StripQuotes( arg2 ) );
|
|
|
|
// UNC names fix
|
|
|
|
if ( ( *(arg2+1) != COLON ) && ( ! ( ( *arg2 == BSLASH ) && ( *(arg2+1) == BSLASH ) ) ) ) {
|
|
arg22[0] = SaveDir[0]; /* get drive we're using */
|
|
arg22[1] = COLON;
|
|
arg22[2] = NULLC;
|
|
if ((mystrlen(arg22) + mystrlen(arg2)+1) > MAX_PATH) {
|
|
ErrorDisplayAndJump( MSG_REN_INVAL_PATH_FILENAME );
|
|
}
|
|
mystrcat( arg22, arg2 ) ;
|
|
|
|
} else
|
|
|
|
{
|
|
mystrcpy(arg22,arg2) ;
|
|
}
|
|
}
|
|
|
|
|
|
/* source = complete path for arg1 */
|
|
|
|
if ( i = FullPath(source, arg1,sizpath1) ) {
|
|
ErrorDisplayAndJump( MSG_REN_INVAL_PATH_FILENAME );
|
|
}
|
|
|
|
//
|
|
// If preserve file name portion from arg1 as FullPath will map *. to * which
|
|
// is not what the user wants.
|
|
//
|
|
if (!((*a1info)->buf->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
|
|
p1 = mystrrchr(source,PathChar) ;
|
|
if (p1 != NULL)
|
|
p1 += 1;
|
|
else
|
|
p1 = source;
|
|
p2 = mystrrchr((*a1info)->fnptr,PathChar) ;
|
|
if (p2 == NULL)
|
|
p2 = (*a1info)->fnptr;
|
|
mystrcpy(p1, p2);
|
|
}
|
|
|
|
/* target = complete path for arg2 */
|
|
|
|
|
|
if ( i = FullPath(target, arg22,sizpath2) ) {
|
|
ErrorDisplayAndJump( MSG_REN_INVAL_PATH_FILENAME );
|
|
}
|
|
|
|
|
|
concat_flag = FALSE ;
|
|
DosErr = NO_ERROR ;
|
|
SetLastError(NO_ERROR);
|
|
*is_dest_dir = 0;
|
|
|
|
if (*lastc(target) == PathChar) { /* test for last non DBCS character path char @@5@J3 */
|
|
concat_flag = TRUE ;
|
|
target[mystrlen(target)-1] = NULLC ;
|
|
};
|
|
|
|
if ( (att = GetFileAttributes( target )) != -1 ) {
|
|
if (att & FILE_ATTRIBUTE_DIRECTORY) { /* if target is a directory, copy the file */
|
|
/* name from source. */
|
|
*is_dest_dir = 1;
|
|
concat_flag = TRUE ;
|
|
};
|
|
} else if ( (DosErr = GetLastError()) &&
|
|
( ( DosErr != ERROR_FILE_NOT_FOUND ) &&
|
|
( DosErr != ERROR_PATH_NOT_FOUND ) ) ) {
|
|
ErrorDisplayAndJump( DosErr );
|
|
};
|
|
|
|
if (concat_flag) {
|
|
arg1 = mystrrchr(source,PathChar);
|
|
if ((mystrlen(arg1) + mystrlen(target) + 1) > MAX_PATH) {
|
|
ErrorDisplayAndJump( MSG_REN_INVAL_PATH_FILENAME );
|
|
}
|
|
mystrcat( target, arg1 ) ;
|
|
};
|
|
|
|
return(SUCCESS) ;
|
|
}
|
|
|
|
|
|
BOOL
|
|
MyMoveFile(
|
|
TCHAR *src,
|
|
TCHAR *dst,
|
|
BOOL *promptokay,
|
|
BOOL *file_moved
|
|
)
|
|
{
|
|
DWORD dwFlags;
|
|
|
|
dwFlags = MOVEFILE_COPY_ALLOWED;
|
|
if (!*promptokay) {
|
|
dwFlags |= MOVEFILE_REPLACE_EXISTING;
|
|
}
|
|
|
|
*file_moved = FALSE;
|
|
if (!MoveFileEx(src, dst, dwFlags)) {
|
|
if (GetLastError() == ERROR_ALREADY_EXISTS) {
|
|
switch (PromptUser(dst, MSG_MOVE_COPY_OVERWRITE, MSG_NOYESALL_RESPONSE_DATA)) {
|
|
case 0: // No
|
|
return TRUE;
|
|
break;
|
|
case 2: // All
|
|
*promptokay = FALSE;
|
|
default: // Yes
|
|
dwFlags |= MOVEFILE_REPLACE_EXISTING;
|
|
return(*file_moved = MoveFileEx(src, dst, dwFlags));
|
|
break;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
} else {
|
|
*file_moved = TRUE;
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
/********************* START OF SPECIFICATION **************************/
|
|
/* */
|
|
/* SUBROUTINE NAME: Move */
|
|
/* */
|
|
/* DESCRIPTIVE NAME: Move Process */
|
|
/* */
|
|
/* FUNCTION: Moves one or more files from directory to another */
|
|
/* directory on the same drive. If you prefer you can give */
|
|
/* the files different names. */
|
|
/* */
|
|
/* NOTES: ( New routine for Release 1.2 ) @@5* */
|
|
/* */
|
|
/* ENTRY POINT: eMove */
|
|
/* LINKAGE: NEAR */
|
|
/* */
|
|
/* INPUT: ptr1 - pointer to [drive:][path]filename to be moved from */
|
|
/* ptr2 - pointer to [path]filename to be moved to */
|
|
/* a1info - pointer to cpyinfo which has arg1 fspec info */
|
|
/* is_dest_dir - from MoveParse() */
|
|
/* */
|
|
/* OUTPUT: None. */
|
|
/* */
|
|
/* EXIT-NORMAL: */
|
|
/* Return Success to the caller. */
|
|
/* */
|
|
/* EXIT-ERROR: */
|
|
/* Return error code from DosMove API. */
|
|
/* */
|
|
/* EFFECTS: None. */
|
|
/* */
|
|
/* INTERNAL REFERENCES: */
|
|
/* ROUTINES: */
|
|
/* ChangeDir - Change back to the original directory. */
|
|
/* ffirst - Find the first file which matches the specified */
|
|
/* file name that may contain * or ?. */
|
|
/* fnext - Find the next file which matches the specified */
|
|
/* file name that may contain * or ?. */
|
|
/* findclose - Close the file with the specified file handle, */
|
|
/* hnFirst which is given by ffirst or fnext. */
|
|
/* PutStdErr - Displays an error message. */
|
|
/* PutStdOut - Displays a message. */
|
|
/* Wild - check if the arg contains wild card. */
|
|
/* */
|
|
/* EXTERNAL REFERENCES: */
|
|
/* ROUTINES: */
|
|
/* DOSMOVE - move directories and files. */
|
|
/* */
|
|
/********************** END OF SPECIFICATION **************************/
|
|
|
|
int
|
|
Move( arg1, arg2, promptokay, a1info, is_dest_dir )
|
|
TCHAR *arg1 ; /* Ptr to 1st arg */
|
|
TCHAR *arg2 ; /* Ptr to 2nd arg */
|
|
BOOL promptokay ;
|
|
PCPYINFO a1info ; /* Holds arg1 fspec info */
|
|
unsigned int is_dest_dir; /* flag if set--> dest. is a dir */
|
|
|
|
{
|
|
unsigned attr ;
|
|
unsigned i, n;
|
|
unsigned long number_of_files_moved ;
|
|
TCHAR Source[MAX_PATH]; /* path of source file */
|
|
TCHAR bufdst[MAX_PATH]; /* path of destination file*/
|
|
HANDLE hnFirst ; /* Findfirst handle */
|
|
TCHAR *j, *k,*l; /* Tmp Ptr */
|
|
unsigned wild_flag ; /* wildcard flag */
|
|
BOOL file_moved;
|
|
unsigned save_error ; /* Saved error code */
|
|
TCHAR pcstr[3] ;
|
|
unsigned rc;
|
|
int retc;
|
|
int how_many_src=0; /* =f_RET_DIR if dir; =0 if none; = <number matching src files> else */
|
|
char type_format_dest=0; /* decide on how to format dest */
|
|
char fl_move_once=0; /* if =1 execute move once only */
|
|
|
|
|
|
|
|
how_many_src = f_how_many (arg1, (ULONG) (attr=FILE_ATTRIBUTE_ARCHIVE) );
|
|
|
|
|
|
/**********************************************/
|
|
/* Set flag whether arg1 contains */
|
|
/* wildcard or not. */
|
|
/**********************************************/
|
|
|
|
pcstr[0] = STAR ;
|
|
pcstr[1] = QMARK ;
|
|
pcstr[2] = NULLC ;
|
|
wild_flag = ((mystrcspn(arg1,pcstr))
|
|
< mystrlen(arg1)) ;
|
|
|
|
|
|
|
|
// Decide on what to do depending on: <1.multiple/single src; 2.is dest dir ?>
|
|
|
|
if (how_many_src == f_RET_DIR) {
|
|
if (is_dest_dir) {
|
|
if (!MyMoveFile(arg1, arg2, &promptokay, &file_moved) ) {
|
|
|
|
i = GetLastError();
|
|
|
|
if (i == ERROR_ALREADY_EXISTS) {
|
|
i = MSG_DUP_FILENAME_OR_NOT_FD;
|
|
}
|
|
|
|
ErrorDisplayAndJump( i );
|
|
} else {
|
|
RestoreSavedDirectory( );
|
|
|
|
return(SUCCESS) ;
|
|
}
|
|
} else {
|
|
type_format_dest = 2;
|
|
fl_move_once = 1;
|
|
}
|
|
}
|
|
|
|
else if (how_many_src > 1 ) {
|
|
if (is_dest_dir) {
|
|
type_format_dest = 1;
|
|
fl_move_once = 0;
|
|
} else {
|
|
ErrorDisplayAndJump( MSG_MOVE_MULTIPLE_FAIL );
|
|
}
|
|
}
|
|
|
|
else { // single source or source doesn't exist
|
|
if (is_dest_dir) {
|
|
type_format_dest = 1;
|
|
fl_move_once = 1;
|
|
} else {
|
|
type_format_dest = 2;
|
|
fl_move_once = 1;
|
|
}
|
|
}
|
|
|
|
|
|
/**********************************************/
|
|
/* Issue ffirst for a file name */
|
|
/**********************************************/
|
|
|
|
/*M006*/ if (!ffirst(arg1, attr = FILE_ATTRIBUTE_ARCHIVE, a1info->buf, &hnFirst )) {
|
|
|
|
/**********************************************/
|
|
/* Issue ffirst for a directory name */
|
|
/**********************************************/
|
|
|
|
rc = ffirst(arg1, attr = FILE_ATTRIBUTE_DIRECTORY, a1info->buf, &hnFirst ) ;
|
|
|
|
if ( !rc) {
|
|
/**********************************************/
|
|
/* No file or directory which arg1 */
|
|
/* specifies found */
|
|
/**********************************************/
|
|
|
|
if (!rc && DosErr == ERROR_NO_MORE_FILES) { /* @@5e */
|
|
rc = ERROR_FILE_NOT_FOUND;
|
|
} else if (wild_flag) {
|
|
rc = MSG_DUP_FILENAME_OR_NOT_FD;
|
|
} else {
|
|
rc = DosErr;
|
|
}
|
|
ErrorDisplayAndJump( rc );
|
|
}
|
|
}
|
|
|
|
number_of_files_moved = 0 ; /* Reset the counter to zero */
|
|
save_error = NO_ERROR ; /* Reset error code to zero */
|
|
mystrcpy(Source,arg1) ;
|
|
j = mystrrchr(Source,PathChar) ;
|
|
++j; /* get to filename area */
|
|
|
|
|
|
do {
|
|
if (CtrlCSeen) {
|
|
findclose(hnFirst) ;
|
|
RestoreSavedDirectory( );
|
|
|
|
return(FAILURE);
|
|
}
|
|
|
|
/**********************************************/
|
|
/* build bufdst */
|
|
/**********************************************/
|
|
|
|
|
|
mystrcpy(j,a1info->buf->cFileName) ;
|
|
|
|
mystrcpy(bufdst,arg2);
|
|
|
|
if (type_format_dest == 1 ) {
|
|
l = mystrrchr(bufdst,PathChar);
|
|
++l;
|
|
mystrcpy(l,a1info->buf->cFileName) ;
|
|
if ((mystrlen(bufdst) ) > MAX_PATH) {
|
|
ErrorDisplayAndJump( MSG_REN_INVAL_PATH_FILENAME ) ;
|
|
}
|
|
}
|
|
|
|
|
|
/**********************************************/
|
|
/* check to see if filename is legal */
|
|
/**********************************************/
|
|
|
|
{
|
|
TCHAR TempBuffer[MAX_PATH];
|
|
DWORD Length;
|
|
|
|
Length = GetFullPathName( bufdst, MAX_PATH, TempBuffer, NULL );
|
|
if (Length == 0 || Length >= MAX_PATH) {
|
|
goto badness;
|
|
}
|
|
|
|
n = _tcslen( TempBuffer );
|
|
|
|
Length = GetFullPathName( Source, MAX_PATH, TempBuffer, NULL );
|
|
if (Length == 0 || Length >= MAX_PATH) {
|
|
goto badness;
|
|
}
|
|
if (!GreatestLength( TempBuffer, &i))
|
|
continue;
|
|
|
|
i -= _tcslen( TempBuffer );
|
|
}
|
|
|
|
if (n + i > MAX_PATH) {
|
|
i = ERROR_FILENAME_EXCED_RANGE;
|
|
goto badness2;
|
|
}
|
|
|
|
/**********************************************/
|
|
/* Move a file or directory */
|
|
/**********************************************/
|
|
|
|
|
|
if (!MyMoveFile(Source, bufdst, &promptokay, &file_moved)) {
|
|
|
|
/**********************************************/
|
|
/* Move fails */
|
|
/**********************************************/
|
|
badness:
|
|
i = GetLastError();
|
|
badness2:
|
|
|
|
if (i == ERROR_ALREADY_EXISTS) {
|
|
i = MSG_DUP_FILENAME_OR_NOT_FD;
|
|
}
|
|
|
|
save_error = i ; /* Save the error code */
|
|
|
|
PutStdErr(i, NOARGS); /* Put out an error message */
|
|
|
|
i = mystrlen(bufdst) ;
|
|
|
|
if ( bufdst[--i] == DOT ) { /* @@5a */
|
|
bufdst[i] = 0 ; /* @@5a */
|
|
} /* @@5a */
|
|
/* @@5a */
|
|
/*509*/if (!_tcsicmp(Source,bufdst)) { /* @@5a */
|
|
break ; /* @@5a */
|
|
} /* @@5a */
|
|
|
|
} else
|
|
if (file_moved) {
|
|
number_of_files_moved += 1;
|
|
if ( wild_flag ) { /* If wild card is used */
|
|
cmd_printf(Fmt17,Source); /* display the file name*/
|
|
}
|
|
|
|
}
|
|
|
|
if (fl_move_once)
|
|
break;
|
|
|
|
} while (fnext(a1info->buf, attr, hnFirst ));
|
|
|
|
|
|
/**********************************************/
|
|
/* No more files to be found */
|
|
/**********************************************/
|
|
|
|
findclose(hnFirst) ;
|
|
RestoreSavedDirectory( );
|
|
|
|
/**********************************************/
|
|
/* Display the total number of file(s) moved */
|
|
/**********************************************/
|
|
|
|
if ( (a1info->buf->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0 ) {
|
|
PutStdOut(MSG_FILES_MOVED, ONEARG,
|
|
argstr1(TEXT("%9d"), (unsigned long)number_of_files_moved)) ;
|
|
}
|
|
|
|
return(save_error == NO_ERROR ? SUCCESS : FAILURE) ;
|
|
}
|
|
|
|
|
|
int
|
|
eTitle (
|
|
|
|
IN struct cmdnode *pcmdnode
|
|
) {
|
|
|
|
LPTSTR NewTitle;
|
|
if (!pszTitleCur) {
|
|
|
|
pszTitleCur = HeapAlloc(GetProcessHeap(), 0, MAX_PATH*sizeof(TCHAR) + 2*sizeof(TCHAR));
|
|
if (pszTitleCur == NULL) {
|
|
|
|
PutStdErr(ERROR_NOT_ENOUGH_MEMORY, NOARGS);
|
|
return( FAILURE );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (mystrlen(pcmdnode->argptr) >= MAX_PATH) {
|
|
|
|
PutStdErr(ERROR_NOT_ENOUGH_MEMORY, NOARGS);
|
|
return( FAILURE );
|
|
|
|
}
|
|
|
|
NewTitle = EatWS(pcmdnode->argptr, NULL);
|
|
if (NewTitle && *NewTitle) {
|
|
mystrcpy(pszTitleCur,NewTitle);
|
|
}
|
|
SetConsoleTitle(pszTitleCur);
|
|
|
|
//
|
|
// This insures that ResetConTitle does not undo what
|
|
// we have just done
|
|
//
|
|
fTitleChanged = FALSE;
|
|
return( SUCCESS );
|
|
}
|
|
|
|
/*** eStart - Entry point for Start routine
|
|
*
|
|
* Purpose:
|
|
* to call Start and pass it a pointer to the command line
|
|
* arguments
|
|
*
|
|
* Args:
|
|
* a pointer to the command node structure
|
|
*
|
|
*/
|
|
|
|
int eStart( n ) /* @@ */
|
|
struct cmdnode *n; /* @@ */
|
|
{ /* @@ */
|
|
DBG_UNREFERENCED_PARAMETER( n );
|
|
return( Start(n->argptr) );
|
|
} /* @@ */
|