📄 copy.c
字号:
/*
* COPY.C -- copy internal command.
*
*
* History:
*
* 01-Aug-98 (Rob Lake z63rrl@morgan.ucs.mun.ca)
* started
*
* 13-Aug-1998 (John P. Price)
* fixed memory leak problem in copy function.
* fixed copy function so it would work with wildcards in the source
*
* 13-Dec-1998 (Eric Kohl)
* Added COPY command to CMD.
*
* 26-Jan-1998 (Eric Kohl)
* Replaced CRT io functions by Win32 io functions.
*
* 27-Oct-1998 (Eric Kohl)
* Disabled prompting when used in batch mode.
*
* 03-Apr-2005 (Magnus Olsen) <magnus@greatlord.com>)
* Remove all hardcode string to En.rc
*
* 13-Jul-2005 (Brandon Turner) <turnerb7@msu.edu>)
* Rewrite to clean up copy and support wildcard.
*
* 20-Jul-2005 (Brandon Turner) <turnerb7@msu.edu>)
* Add touch syntax. "copy arp.exe+,,"
* Copy command is now completed.
*/
#include <precomp.h>
#ifdef INCLUDE_CMD_COPY
enum
{
COPY_ASCII = 0x001, /* /A */
COPY_DECRYPT = 0x004, /* /D */
COPY_VERIFY = 0x008, /* /V : Dummy, Never will be Impleneted */
COPY_SHORTNAME = 0x010, /* /N : Dummy, Never will be Impleneted */
COPY_NO_PROMPT = 0x020, /* /Y */
COPY_PROMPT = 0x040, /* /-Y */
COPY_RESTART = 0x080, /* /Z */
COPY_BINARY = 0x100, /* /B */
};
#define BUFF_SIZE 16384 /* 16k = max buffer size */
INT
copy (TCHAR source[MAX_PATH],
TCHAR dest[MAX_PATH],
INT append,
DWORD lpdwFlags,
BOOL bTouch)
{
TCHAR szMsg[RC_STRING_MAX_SIZE];
FILETIME srctime,NewFileTime;
HANDLE hFileSrc;
HANDLE hFileDest;
LPBYTE buffer;
DWORD dwAttrib;
DWORD dwRead;
DWORD dwWritten;
BOOL bEof = FALSE;
TCHAR TrueDest[MAX_PATH];
TCHAR TempSrc[MAX_PATH];
TCHAR * FileName;
SYSTEMTIME CurrentTime;
/* Check Breaker */
if(CheckCtrlBreak(BREAK_INPUT))
return 0;
#ifdef _DEBUG
DebugPrintf (_T("checking mode\n"));
#endif
if(bTouch)
{
hFileSrc = CreateFile (source, GENERIC_WRITE, FILE_SHARE_READ,
NULL, OPEN_EXISTING, 0, NULL);
if (hFileSrc == INVALID_HANDLE_VALUE)
{
LoadString(CMD_ModuleHandle, STRING_COPY_ERROR1, szMsg, RC_STRING_MAX_SIZE);
ConOutPrintf(szMsg, source);
nErrorLevel = 1;
return 0;
}
GetSystemTime(&CurrentTime);
SystemTimeToFileTime(&CurrentTime, &NewFileTime);
if(SetFileTime(hFileSrc,(LPFILETIME) NULL, (LPFILETIME) NULL, &NewFileTime))
{
CloseHandle(hFileSrc);
nErrorLevel = 1;
return 1;
}
else
{
CloseHandle(hFileSrc);
return 0;
}
}
dwAttrib = GetFileAttributes (source);
hFileSrc = CreateFile (source, GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, 0, NULL);
if (hFileSrc == INVALID_HANDLE_VALUE)
{
LoadString(CMD_ModuleHandle, STRING_COPY_ERROR1, szMsg, RC_STRING_MAX_SIZE);
ConOutPrintf(szMsg, source);
nErrorLevel = 1;
return 0;
}
#ifdef _DEBUG
DebugPrintf (_T("getting time\n"));
#endif
GetFileTime (hFileSrc, &srctime, NULL, NULL);
#ifdef _DEBUG
DebugPrintf (_T("copy: flags has %s\n"),
lpdwFlags & COPY_ASCII ? "ASCII" : "BINARY");
#endif
/* Check to see if /D or /Z are true, if so we need a middle
man to copy the file too to allow us to use CopyFileEx later */
if(lpdwFlags & COPY_DECRYPT)
{
GetEnvironmentVariable(_T("TEMP"),TempSrc,MAX_PATH);
_tcscat(TempSrc,_T("\\"));
FileName = _tcsrchr(source,_T('\\'));
FileName++;
_tcscat(TempSrc,FileName);
/* This is needed to be on the end to prevent an error
if the user did "copy /D /Z foo bar then it would be copied
too %TEMP%\foo here and when %TEMP%\foo when it sets it up
for COPY_RESTART, this would mean it is copying to itself
which would error when it tried to open the handles for ReadFile
and WriteFile */
_tcscat(TempSrc,_T(".decrypt"));
if(!CopyFileEx(source, TempSrc, NULL, NULL, FALSE, COPY_FILE_ALLOW_DECRYPTED_DESTINATION))
{
nErrorLevel = 1;
return 0;
}
_tcscpy(source, TempSrc);
}
if(lpdwFlags & COPY_RESTART)
{
_tcscpy(TrueDest, dest);
GetEnvironmentVariable(_T("TEMP"),dest,MAX_PATH);
_tcscat(dest,_T("\\"));
FileName = _tcsrchr(TrueDest,_T('\\'));
FileName++;
_tcscat(dest,FileName);
}
if (!IsExistingFile (dest))
{
#ifdef _DEBUG
DebugPrintf (_T("opening/creating\n"));
#endif
hFileDest =
CreateFile (dest, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
}
else if (!append)
{
if (!_tcscmp (dest, source))
{
LoadString(CMD_ModuleHandle, STRING_COPY_ERROR2, szMsg, RC_STRING_MAX_SIZE);
ConOutPrintf(szMsg, source);
CloseHandle (hFileSrc);
nErrorLevel = 1;
return 0;
}
#ifdef _DEBUG
DebugPrintf (_T("SetFileAttributes (%s, FILE_ATTRIBUTE_NORMAL);\n"), dest);
#endif
SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
#ifdef _DEBUG
DebugPrintf (_T("DeleteFile (%s);\n"), dest);
#endif
DeleteFile (dest);
hFileDest = CreateFile (dest, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
}
else
{
LONG lFilePosHigh = 0;
if (!_tcscmp (dest, source))
{
CloseHandle (hFileSrc);
return 0;
}
#ifdef _DEBUG
DebugPrintf (_T("opening/appending\n"));
#endif
SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
hFileDest =
CreateFile (dest, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
/* Move to end of file to start writing */
SetFilePointer (hFileDest, 0, &lFilePosHigh,FILE_END);
}
if (hFileDest == INVALID_HANDLE_VALUE)
{
CloseHandle (hFileSrc);
ConOutResPuts(STRING_ERROR_PATH_NOT_FOUND);
nErrorLevel = 1;
return 0;
}
/* A page-aligned buffer usually give more speed */
buffer = (LPBYTE)VirtualAlloc(NULL, BUFF_SIZE, MEM_COMMIT, PAGE_READWRITE);
if (buffer == NULL)
{
CloseHandle (hFileDest);
CloseHandle (hFileSrc);
ConOutResPuts(STRING_ERROR_OUT_OF_MEMORY);
nErrorLevel = 1;
return 0;
}
do
{
ReadFile (hFileSrc, buffer, BUFF_SIZE, &dwRead, NULL);
if (lpdwFlags & COPY_ASCII)
{
LPBYTE pEof = memchr(buffer, 0x1A, dwRead);
if (pEof != NULL)
{
bEof = TRUE;
dwRead = pEof-buffer+1;
break;
}
}
if (dwRead == 0)
break;
WriteFile (hFileDest, buffer, dwRead, &dwWritten, NULL);
if (dwWritten != dwRead || CheckCtrlBreak(BREAK_INPUT))
{
ConOutResPuts(STRING_COPY_ERROR3);
cmd_free (buffer);
CloseHandle (hFileDest);
CloseHandle (hFileSrc);
nErrorLevel = 1;
return 0;
}
}
while (!bEof);
#ifdef _DEBUG
DebugPrintf (_T("setting time\n"));
#endif
SetFileTime (hFileDest, &srctime, NULL, NULL);
if ((lpdwFlags & COPY_ASCII) && !bEof)
{
/* we're dealing with ASCII files! */
buffer[0] = 0x1A;
#ifdef _DEBUG
DebugPrintf (_T("appending ^Z\n"));
#endif
WriteFile (hFileDest, buffer, sizeof(CHAR), &dwWritten, NULL);
}
VirtualFree (buffer, 0, MEM_RELEASE);
CloseHandle (hFileDest);
CloseHandle (hFileSrc);
#ifdef _DEBUG
DebugPrintf (_T("setting mode\n"));
#endif
SetFileAttributes (dest, dwAttrib);
/* Now finish off the copy if needed with CopyFileEx */
if(lpdwFlags & COPY_RESTART)
{
if(!CopyFileEx(dest, TrueDest, NULL, NULL, FALSE, COPY_FILE_RESTARTABLE))
{
nErrorLevel = 1;
DeleteFile(dest);
return 0;
}
/* Take care of file in the temp folder */
DeleteFile(dest);
}
if(lpdwFlags & COPY_DECRYPT)
DeleteFile(TempSrc);
return 1;
}
static INT CopyOverwrite (LPTSTR fn)
{
/*ask the user if they want to override*/
TCHAR szMsg[RC_STRING_MAX_SIZE];
INT res;
LoadString(CMD_ModuleHandle, STRING_COPY_HELP1, szMsg, RC_STRING_MAX_SIZE);
ConOutPrintf(szMsg,fn);
res = FilePromptYNA (_T(""));
return res;
}
INT cmd_copy (LPTSTR cmd, LPTSTR param)
{
TCHAR szMsg[RC_STRING_MAX_SIZE];
LPTSTR *arg;
INT argc, i, nFiles, nOverwrite = 0, nSrc = -1, nDes = -1;
/* this is the path up to the folder of the src and dest ie C:\windows\ */
TCHAR szDestPath[MAX_PATH];
TCHAR szSrcPath[MAX_PATH];
DWORD dwFlags = 0;
/* If this is the type of copy where we are adding files */
BOOL bAppend = FALSE;
WIN32_FIND_DATA findBuffer;
HANDLE hFile;
BOOL bTouch = FALSE;
/* Used when something like "copy c*.exe d*.exe" during the process of
figuring out the new name */
TCHAR tmpName[MAX_PATH] = _T("");
/* Pointer to keep track of how far through the append input(file1+file2+file3) we are */
TCHAR * appendPointer = _T("\0");
/* The full path to src and dest. This has drive letter, folders, and filename */
TCHAR tmpDestPath[MAX_PATH];
TCHAR tmpSrcPath[MAX_PATH];
/* A bool on weather or not the destination name will be taking from the input */
BOOL bSrcName = FALSE;
/* Seems like a waste but it is a pointer used to copy from input to PreserveName */
TCHAR * UseThisName;
/* Stores the name( i.e. blah.txt or blah*.txt) which later we might need */
TCHAR PreserveName[MAX_PATH];
/* for CMDCOPY env */
TCHAR *evar;
int size;
TCHAR * szTouch;
BOOL bDone = FALSE;
/*Show help/usage info*/
if (!_tcsncmp (param, _T("/?"), 2))
{
ConOutResPaging(TRUE, STRING_COPY_HELP2);
return 0;
}
nErrorLevel = 0;
/* Get the envor value if it exists */
evar = cmd_alloc(512 * sizeof(TCHAR));
if (evar==NULL) size = 0;
else
{
size = GetEnvironmentVariable (_T("COPYCMD"), evar, 512);
}
if (size > 512)
{
evar = cmd_realloc(evar,size * sizeof(TCHAR) );
if (evar!=NULL)
{
size = GetEnvironmentVariable (_T("COPYCMD"), evar, size);
}
else
{
size=0;
}
}
/* check see if we did get any env variable */
if (size !=0)
{
int t=0;
/* scan and set the flags */
for (t=0;t<size;t++)
{
if (_tcsncicmp(_T("/A"),&evar[t],2)==0)
{
dwFlags |=COPY_ASCII;
t++;
}
else if (_tcsncicmp(_T("/B"),&evar[t],2)==0)
{
dwFlags |= COPY_BINARY;
t++;
}
else if (_tcsncicmp(_T("/D"),&evar[t],2)==0)
{
dwFlags |= COPY_DECRYPT;
t++;
}
else if (_tcsncicmp(_T("/V"),&evar[t],2)==0)
{
dwFlags |= COPY_VERIFY;
t++;
}
else if (_tcsncicmp(_T("/N"),&evar[t],2)==0)
{
dwFlags |= COPY_SHORTNAME;
t++;
}
else if (_tcsncicmp(_T("/Y"),&evar[t],2)==0)
{
dwFlags |= COPY_NO_PROMPT;
t++;
}
else if (_tcsncicmp(_T("/-Y"),&evar[t],3)==0)
{
dwFlags |= COPY_PROMPT;
t+=2;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -