Crtl-C gives a new line when reading input
[reactos.git] / reactos / subsys / system / cmd / copy.c
1 /*
2 * COPY.C -- copy internal command.
3 *
4 *
5 * History:
6 *
7 * 01-Aug-98 (Rob Lake z63rrl@morgan.ucs.mun.ca)
8 * started
9 *
10 * 13-Aug-1998 (John P. Price)
11 * fixed memory leak problem in copy function.
12 * fixed copy function so it would work with wildcards in the source
13 *
14 * 13-Dec-1998 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
15 * Added COPY command to CMD.
16 *
17 * 26-Jan-1998 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
18 * Replaced CRT io functions by Win32 io functions.
19 *
20 * 27-Oct-1998 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
21 * Disabled prompting when used in batch mode.
22 *
23 * 03-Apr-2005 (Magnus Olsen) <magnus@greatlord.com>)
24 * Remove all hardcode string to En.rc
25 *
26 * 13-Jul-2005 (Brandon Turner) <turnerb7@msu.edu>)
27 * Rewrite to clean up copy and support wildcard.
28 *
29 * 20-Jul-2005 (Brandon Turner) <turnerb7@msu.edu>)
30 * Add touch syntax. "copy arp.exe+,,"
31 * Copy command is now completed.
32 */
33
34 #include <precomp.h>
35 #include "resource.h"
36
37 #ifdef INCLUDE_CMD_COPY
38
39 enum
40 {
41 COPY_ASCII = 0x001, /* /A */
42 COPY_DECRYPT = 0x004, /* /D */
43 COPY_VERIFY = 0x008, /* /V : Dummy, Never will be Impleneted */
44 COPY_SHORTNAME = 0x010, /* /N : Dummy, Never will be Impleneted */
45 COPY_NO_PROMPT = 0x020, /* /Y */
46 COPY_PROMPT = 0x040, /* /-Y */
47 COPY_RESTART = 0x080, /* /Z */
48 COPY_BINARY = 0x100, /* /B */
49 };
50
51 #define BUFF_SIZE 16384 /* 16k = max buffer size */
52
53
54 INT
55 copy (TCHAR source[MAX_PATH],
56 TCHAR dest[MAX_PATH],
57 INT append,
58 DWORD lpdwFlags,
59 BOOL bTouch)
60 {
61 TCHAR szMsg[RC_STRING_MAX_SIZE];
62 FILETIME srctime,NewFileTime;
63 HANDLE hFileSrc;
64 HANDLE hFileDest;
65 LPBYTE buffer;
66 DWORD dwAttrib;
67 DWORD dwRead;
68 DWORD dwWritten;
69 DWORD i;
70 BOOL bEof = FALSE;
71 TCHAR TrueDest[MAX_PATH];
72 TCHAR TempSrc[MAX_PATH];
73 TCHAR * FileName;
74 SYSTEMTIME CurrentTime;
75
76 /* Check Breaker */
77 if(CheckCtrlBreak(BREAK_INPUT))
78 return 0;
79
80 #ifdef _DEBUG
81 DebugPrintf (_T("checking mode\n"));
82 #endif
83
84 if(bTouch)
85 {
86 hFileSrc = CreateFile (source, GENERIC_WRITE, FILE_SHARE_READ,
87 NULL, OPEN_EXISTING, 0, NULL);
88 if (hFileSrc == INVALID_HANDLE_VALUE)
89 {
90 LoadString(CMD_ModuleHandle, STRING_COPY_ERROR1, szMsg, RC_STRING_MAX_SIZE);
91 ConOutPrintf(szMsg, source);
92 nErrorLevel = 1;
93 return 0;
94 }
95
96 GetSystemTime(&CurrentTime);
97 SystemTimeToFileTime(&CurrentTime, &NewFileTime);
98 if(SetFileTime(hFileSrc,(LPFILETIME) NULL, (LPFILETIME) NULL, &NewFileTime))
99 {
100 CloseHandle(hFileSrc);
101 nErrorLevel = 1;
102 return 1;
103
104 }
105 else
106 {
107 CloseHandle(hFileSrc);
108 return 0;
109 }
110 }
111
112 dwAttrib = GetFileAttributes (source);
113
114 hFileSrc = CreateFile (source, GENERIC_READ, FILE_SHARE_READ,
115 NULL, OPEN_EXISTING, 0, NULL);
116 if (hFileSrc == INVALID_HANDLE_VALUE)
117 {
118 LoadString(CMD_ModuleHandle, STRING_COPY_ERROR1, szMsg, RC_STRING_MAX_SIZE);
119 ConOutPrintf(szMsg, source);
120 nErrorLevel = 1;
121 return 0;
122 }
123
124 #ifdef _DEBUG
125 DebugPrintf (_T("getting time\n"));
126 #endif
127
128 GetFileTime (hFileSrc, &srctime, NULL, NULL);
129
130 #ifdef _DEBUG
131 DebugPrintf (_T("copy: flags has %s\n"),
132 lpdwFlags & COPY_ASCII ? "ASCII" : "BINARY");
133 #endif
134
135 /* Check to see if /D or /Z are true, if so we need a middle
136 man to copy the file too to allow us to use CopyFileEx later */
137 if(lpdwFlags & COPY_DECRYPT)
138 {
139 GetEnvironmentVariable(_T("TEMP"),TempSrc,MAX_PATH);
140 _tcscat(TempSrc,_T("\\"));
141 FileName = _tcsrchr(source,_T('\\'));
142 FileName++;
143 _tcscat(TempSrc,FileName);
144 /* This is needed to be on the end to prevent an error
145 if the user did "copy /D /Z foo bar then it would be copied
146 too %TEMP%\foo here and when %TEMP%\foo when it sets it up
147 for COPY_RESTART, this would mean it is copying to itself
148 which would error when it tried to open the handles for ReadFile
149 and WriteFile */
150 _tcscat(TempSrc,_T(".decrypt"));
151 if(!CopyFileEx(source, TempSrc, NULL, NULL, FALSE, COPY_FILE_ALLOW_DECRYPTED_DESTINATION))
152 {
153 nErrorLevel = 1;
154 return 0;
155 }
156 _tcscpy(source, TempSrc);
157 }
158
159
160 if(lpdwFlags & COPY_RESTART)
161 {
162 _tcscpy(TrueDest, dest);
163 GetEnvironmentVariable(_T("TEMP"),dest,MAX_PATH);
164 _tcscat(dest,_T("\\"));
165 FileName = _tcsrchr(TrueDest,_T('\\'));
166 FileName++;
167 _tcscat(dest,FileName);
168 }
169
170
171
172 if (!IsExistingFile (dest))
173 {
174 #ifdef _DEBUG
175 DebugPrintf (_T("opening/creating\n"));
176 #endif
177 hFileDest =
178 CreateFile (dest, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
179 }
180 else if (!append)
181 {
182 if (!_tcscmp (dest, source))
183 {
184 LoadString(CMD_ModuleHandle, STRING_COPY_ERROR2, szMsg, RC_STRING_MAX_SIZE);
185 ConOutPrintf(szMsg, source);
186
187 CloseHandle (hFileSrc);
188 nErrorLevel = 1;
189 return 0;
190 }
191
192 #ifdef _DEBUG
193 DebugPrintf (_T("SetFileAttributes (%s, FILE_ATTRIBUTE_NORMAL);\n"), dest);
194 #endif
195 SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
196
197 #ifdef _DEBUG
198 DebugPrintf (_T("DeleteFile (%s);\n"), dest);
199 #endif
200 DeleteFile (dest);
201
202 hFileDest = CreateFile (dest, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
203 }
204 else
205 {
206 LONG lFilePosHigh = 0;
207
208 if (!_tcscmp (dest, source))
209 {
210 CloseHandle (hFileSrc);
211 return 0;
212 }
213
214 #ifdef _DEBUG
215 DebugPrintf (_T("opening/appending\n"));
216 #endif
217 SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
218
219 hFileDest =
220 CreateFile (dest, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
221
222 /* Move to end of file to start writing */
223 SetFilePointer (hFileDest, 0, &lFilePosHigh,FILE_END);
224 }
225
226
227 if (hFileDest == INVALID_HANDLE_VALUE)
228 {
229 CloseHandle (hFileSrc);
230 ConOutResPuts(STRING_ERROR_PATH_NOT_FOUND);
231 nErrorLevel = 1;
232 return 0;
233 }
234 buffer = (LPBYTE)malloc (BUFF_SIZE);
235 if (buffer == NULL)
236 {
237 CloseHandle (hFileDest);
238 CloseHandle (hFileSrc);
239 ConOutResPuts(STRING_ERROR_OUT_OF_MEMORY);
240 nErrorLevel = 1;
241 return 0;
242 }
243
244 do
245 {
246
247 ReadFile (hFileSrc, buffer, BUFF_SIZE, &dwRead, NULL);
248 if (lpdwFlags & COPY_ASCII)
249 {
250 for (i = 0; i < dwRead; i++)
251 {
252 /* we're dealing with ASCII files! */
253 if (((LPSTR)buffer)[i] == 0x1A)
254 {
255 bEof = TRUE;
256 break;
257 }
258 }
259 dwRead = i;
260 }
261
262 if (dwRead == 0)
263 break;
264
265 WriteFile (hFileDest, buffer, dwRead, &dwWritten, NULL);
266 if (dwWritten != dwRead || CheckCtrlBreak(BREAK_INPUT))
267 {
268 ConOutResPuts(STRING_COPY_ERROR3);
269
270 free (buffer);
271 CloseHandle (hFileDest);
272 CloseHandle (hFileSrc);
273 nErrorLevel = 1;
274 return 0;
275 }
276 }
277 while (dwRead && !bEof);
278
279 #ifdef _DEBUG
280 DebugPrintf (_T("setting time\n"));
281 #endif
282 SetFileTime (hFileDest, &srctime, NULL, NULL);
283
284 if (lpdwFlags & COPY_ASCII)
285 {
286 /* we're dealing with ASCII files! */
287 ((LPSTR)buffer)[0] = 0x1A;
288 ((LPSTR)buffer)[1] = '\0';
289 #ifdef _DEBUG
290 DebugPrintf (_T("appending ^Z\n"));
291 #endif
292 WriteFile (hFileDest, buffer, sizeof(CHAR), &dwWritten, NULL);
293 }
294
295 free (buffer);
296 CloseHandle (hFileDest);
297 CloseHandle (hFileSrc);
298
299 #ifdef _DEBUG
300 DebugPrintf (_T("setting mode\n"));
301 #endif
302 SetFileAttributes (dest, dwAttrib);
303
304 /* Now finish off the copy if needed with CopyFileEx */
305 if(lpdwFlags & COPY_RESTART)
306 {
307 if(!CopyFileEx(dest, TrueDest, NULL, NULL, FALSE, COPY_FILE_RESTARTABLE))
308 {
309 nErrorLevel = 1;
310 DeleteFile(dest);
311 return 0;
312 }
313 /* Take care of file in the temp folder */
314 DeleteFile(dest);
315
316 }
317
318 if(lpdwFlags & COPY_DECRYPT)
319 DeleteFile(TempSrc);
320
321
322
323 return 1;
324 }
325
326
327 static INT CopyOverwrite (LPTSTR fn)
328 {
329 /*ask the user if they want to override*/
330 TCHAR szMsg[RC_STRING_MAX_SIZE];
331 INT res;
332 LoadString(CMD_ModuleHandle, STRING_COPY_HELP1, szMsg, RC_STRING_MAX_SIZE);
333 ConOutPrintf(szMsg,fn);
334 res = FilePromptYNA (_T(""));
335 return res;
336 }
337
338
339 INT cmd_copy (LPTSTR cmd, LPTSTR param)
340 {
341 TCHAR szMsg[RC_STRING_MAX_SIZE];
342 LPTSTR *arg;
343 INT argc, i, nFiles, nOverwrite = 0, nSrc = -1, nDes = -1;
344 /* this is the path up to the folder of the src and dest ie C:\windows\ */
345 TCHAR szDestPath[MAX_PATH];
346 TCHAR szSrcPath[MAX_PATH];
347 DWORD dwFlags = 0;
348 /* If this is the type of copy where we are adding files */
349 BOOL bAppend = FALSE;
350 WIN32_FIND_DATA findBuffer;
351 HANDLE hFile;
352 BOOL bTouch = FALSE;
353 /* Used when something like "copy c*.exe d*.exe" during the process of
354 figuring out the new name */
355 TCHAR tmpName[MAX_PATH] = _T("");
356 /* Pointer to keep track of how far through the append input(file1+file2+file3) we are */
357 TCHAR * appendPointer = _T("\0");
358 /* The full path to src and dest. This has drive letter, folders, and filename */
359 TCHAR tmpDestPath[MAX_PATH];
360 TCHAR tmpSrcPath[MAX_PATH];
361 /* A bool on weather or not the destination name will be taking from the input */
362 BOOL bSrcName = FALSE;
363 /* Seems like a waste but it is a pointer used to copy from input to PreserveName */
364 TCHAR * UseThisName;
365 /* Stores the name( i.e. blah.txt or blah*.txt) which later we might need */
366 TCHAR PreserveName[MAX_PATH];
367 /* for CMDCOPY env */
368 TCHAR *evar;
369 int size;
370 TCHAR * szTouch;
371 BOOL bDone = FALSE;
372
373
374 /*Show help/usage info*/
375 if (!_tcsncmp (param, _T("/?"), 2))
376 {
377 ConOutResPaging(TRUE, STRING_COPY_HELP2);
378 return 0;
379 }
380
381 nErrorLevel = 0;
382
383 /* Get the envor value if it exists */
384 evar = malloc(512 * sizeof(TCHAR));
385 if (evar==NULL) size = 0;
386 else
387 {
388 size = GetEnvironmentVariable (_T("COPYCMD"), evar, 512);
389 }
390 if (size > 512)
391 {
392 evar = realloc(evar,size * sizeof(TCHAR) );
393 if (evar!=NULL)
394 {
395 size = GetEnvironmentVariable (_T("COPYCMD"), evar, size);
396 }
397 else
398 {
399 size=0;
400 }
401 }
402
403 /* check see if we did get any env variable */
404 if (size !=0)
405 {
406 int t=0;
407 /* scan and set the flags */
408 for (t=0;t<size;t++)
409 {
410 if (_tcsncicmp(_T("/A"),&evar[t],2)==0)
411 {
412 dwFlags |=COPY_ASCII;
413 t++;
414 }
415
416 else if (_tcsncicmp(_T("/B"),&evar[t],2)==0)
417 {
418 dwFlags |= COPY_BINARY;
419 t++;
420 }
421 else if (_tcsncicmp(_T("/D"),&evar[t],2)==0)
422 {
423 dwFlags |= COPY_DECRYPT;
424 t++;
425 }
426
427 else if (_tcsncicmp(_T("/V"),&evar[t],2)==0)
428 {
429 dwFlags |= COPY_VERIFY;
430 t++;
431 }
432
433 else if (_tcsncicmp(_T("/N"),&evar[t],2)==0)
434 {
435 dwFlags |= COPY_SHORTNAME;
436 t++;
437 }
438
439 else if (_tcsncicmp(_T("/Y"),&evar[t],2)==0)
440 {
441 dwFlags |= COPY_NO_PROMPT;
442 t++;
443 }
444
445 else if (_tcsncicmp(_T("/-Y"),&evar[t],3)==0)
446 {
447 dwFlags |= COPY_PROMPT;
448 t+=2;
449 }
450
451 else if (_tcsncicmp(_T("/Z"),&evar[t],2)==0)
452 {
453 dwFlags |= COPY_PROMPT;
454 t++;
455 }
456 }
457 }
458 free(evar);
459
460
461 /*Split the user input into array*/
462 arg = split (param, &argc, FALSE);
463 nFiles = argc;
464
465
466 /*Read switches and count files*/
467 for (i = 0; i < argc; i++)
468 {
469 if (*arg[i] == _T('/'))
470 {
471 if (_tcslen(arg[i]) >= 2)
472 {
473 switch (_totupper(arg[i][1]))
474 {
475
476 case _T('A'):
477 dwFlags |= COPY_ASCII;
478 break;
479
480 case _T('B'):
481 dwFlags |= COPY_BINARY;
482 break;
483
484 case _T('D'):
485 dwFlags |= COPY_DECRYPT;
486 break;
487
488 case _T('V'):
489 dwFlags |= COPY_VERIFY;
490 break;
491
492 case _T('N'):
493 dwFlags |= COPY_SHORTNAME;
494 break;
495
496 case _T('Y'):
497 dwFlags |= COPY_NO_PROMPT;
498 dwFlags &= ~COPY_PROMPT;
499 break;
500
501 case _T('-'):
502 if(_tcslen(arg[i]) >= 3)
503 if(_totupper(arg[i][2]) == _T('Y'))
504 {
505 dwFlags &= ~COPY_NO_PROMPT;
506 dwFlags |= COPY_PROMPT;
507 }
508
509 break;
510
511 case _T('Z'):
512 dwFlags |= COPY_RESTART;
513 break;
514
515 default:
516 /* invaild switch */
517 LoadString(CMD_ModuleHandle, STRING_ERROR_INVALID_SWITCH, szMsg, RC_STRING_MAX_SIZE);
518 ConOutPrintf(szMsg, _totupper(arg[i][1]));
519 nErrorLevel = 1;
520 return 1;
521 break;
522 }
523 }
524 /*If it was a switch, subtract from total arguments*/
525 nFiles--;
526 }
527 else
528 {
529 /*if it isnt a switch then it is the source or destination*/
530 if(nSrc == -1)
531 {
532 nSrc = i;
533 }
534 else if(*arg[i] == _T('+') || *arg[i] == _T(','))
535 {
536 /* Add these onto the source string
537 this way we can do all checks
538 directly on source string later on */
539 _tcscat(arg[nSrc],arg[i]);
540 nFiles--;
541 }
542 else if(nDes == -1)
543 {
544 nDes = i;
545 }
546
547 }
548 }
549
550 /* keep quiet within batch files */
551 if (bc != NULL)
552 {
553 dwFlags |= COPY_NO_PROMPT;
554 dwFlags &= ~COPY_PROMPT;
555 }
556
557 if(nFiles < 1)
558 {
559 /* There is not enough files, there has to be at least 1 */
560 ConOutResPuts(STRING_ERROR_REQ_PARAM_MISSING);
561 freep (arg);
562 return 1;
563 }
564
565 if(nFiles > 2)
566 {
567 /* there is too many file names in command */
568 LoadString(CMD_ModuleHandle, STRING_ERROR_TOO_MANY_PARAMETERS, szMsg, RC_STRING_MAX_SIZE);
569 ConErrPrintf(szMsg,_T(""));
570 nErrorLevel = 1;
571 freep (arg);
572 return 1;
573 }
574
575 if(((_tcschr (arg[nSrc], _T('+')) != NULL) ||
576 (_tcschr (arg[nSrc], _T('*')) != NULL && _tcschr (arg[nDes], _T('*')) == NULL) ||
577 (IsExistingDirectory (arg[nSrc]) && (_tcschr (arg[nDes], _T('*')) == NULL && !IsExistingDirectory (arg[nDes])))
578 ))
579 {
580 /* There is a + in the source filename, this means
581 that there is more then one file being put into
582 one file. */
583 bAppend = TRUE;
584 if(_tcschr (arg[nSrc], _T('+')) != NULL)
585 appendPointer = arg[nSrc];
586 }
587
588 /* Reusing the number of files variable */
589 nFiles = 0;
590
591 do
592 {
593 /* Set up the string that is the path to the destination */
594 if(nDes != -1)
595 {
596 if(_tcslen(arg[nDes]) == 2 && arg[nDes][1] == _T(':'))
597 {
598 GetRootPath(arg[nDes],szDestPath,MAX_PATH);
599 }
600 else
601 /* If the user entered two file names then form the full string path*/
602 GetFullPathName (arg[nDes], MAX_PATH, szDestPath, NULL);
603
604 }
605 else
606 {
607 /* If no destination was entered then just use
608 the current directory as the destination */
609 GetCurrentDirectory (MAX_PATH, szDestPath);
610 }
611
612
613 /* Get the full string of the path to the source file*/
614 if(_tcschr (arg[nSrc], _T('+')) != NULL)
615 {
616 _tcscpy(tmpName,_T("\0"));
617 /* Loop through the source file name and copy all
618 the chars one at a time until it gets too + */
619 while(TRUE)
620 {
621 if(!_tcsncmp (appendPointer,_T("+"),1) || !_tcsncmp (appendPointer,_T("\0"),1))
622 {
623 /* Now that the pointer is on the + we
624 need to go to the start of the next filename */
625 if(!_tcsncmp (appendPointer,_T("+"),1))
626 appendPointer++;
627 else
628 bDone = TRUE;
629 break;
630
631 }
632
633 _tcsncat(tmpName,appendPointer,1);
634 appendPointer++;
635
636 }
637 /* Finish the string off with a null char */
638 _tcsncat(tmpName,_T("\0"),1);
639
640 if(_tcschr (arg[nSrc], _T(',')) != NULL)
641 {
642 /* Only time there is a , in the source is when they are using touch
643 Cant have a destination and can only have on ,, at the end of the string
644 Cant have more then one file name */
645 szTouch = _tcsstr (arg[nSrc], _T("+"));
646 if(_tcsncmp (szTouch,_T("+,,\0"),4) || nDes != -1)
647 {
648 LoadString(CMD_ModuleHandle, STRING_ERROR_INVALID_PARAM_FORMAT, szMsg, RC_STRING_MAX_SIZE);
649 ConErrPrintf(szMsg,arg[nSrc]);
650 nErrorLevel = 1;
651 freep (arg);
652 return 1;
653 }
654 bTouch = TRUE;
655 bDone = TRUE;
656 }
657
658 if(_tcslen(tmpName) == 2)
659 {
660 if(tmpName[1] == _T(':'))
661 {
662
663 GetRootPath(tmpName,szSrcPath,MAX_PATH);
664 }
665 }
666 else
667 /* Get the full path to first file in the string of file names */
668 GetFullPathName (tmpName, MAX_PATH, szSrcPath, NULL);
669 }
670 else
671 {
672 bDone = TRUE;
673 if(_tcslen(arg[nSrc]) == 2 && arg[nSrc][1] == _T(':'))
674 {
675 GetRootPath(arg[nSrc],szSrcPath,MAX_PATH);
676 }
677 else
678 /* Get the full path of the source file */
679 GetFullPathName (arg[nSrc], MAX_PATH, szSrcPath, NULL);
680
681 }
682
683 /* From this point on, we can assume that the shortest path is 3 letters long
684 and that would be [DriveLetter]:\ */
685
686 /* If there is no * in the path name and it is a folder
687 then we will need to add a wildcard to the pathname
688 so FindFirstFile comes up with all the files in that
689 folder */
690 if(_tcschr (szSrcPath, _T('*')) == NULL &&
691 IsExistingDirectory (szSrcPath))
692 {
693 /* If it doesnt have a \ at the end already then on needs to be added */
694 if(szSrcPath[_tcslen(szSrcPath) - 1] != _T('\\'))
695 _tcscat (szSrcPath, _T("\\"));
696 /* Add a wildcard after the \ */
697 _tcscat (szSrcPath, _T("*"));
698 }
699 /* Make sure there is an ending slash to the path if the dest is a folder */
700 if(_tcschr (szDestPath, _T('*')) == NULL &&
701 IsExistingDirectory(szDestPath))
702 {
703 if(szDestPath[_tcslen(szDestPath) - 1] != _T('\\'))
704 _tcscat (szDestPath, _T("\\"));
705 }
706
707
708 /* Get a list of all the files */
709 hFile = FindFirstFile (szSrcPath, &findBuffer);
710
711
712 /* We need to figure out what the name of the file in the is going to be */
713 if((szDestPath[_tcslen(szDestPath) - 1] == _T('*') && szDestPath[_tcslen(szDestPath) - 2] == _T('\\')) ||
714 szDestPath[_tcslen(szDestPath) - 1] == _T('\\'))
715 {
716 /* In this case we will be using the same name as the source file
717 for the destination file because destination is a folder */
718 bSrcName = TRUE;
719 }
720 else
721 {
722 /* Save the name the user entered */
723 UseThisName = _tcsrchr(szDestPath,_T('\\'));
724 UseThisName++;
725 _tcscpy(PreserveName,UseThisName);
726 }
727
728 /* Strip the paths back to the folder they are in */
729 for(i = (_tcslen(szSrcPath) - 1); i > -1; i--)
730 if(szSrcPath[i] != _T('\\'))
731 szSrcPath[i] = _T('\0');
732 else
733 break;
734
735 for(i = (_tcslen(szDestPath) - 1); i > -1; i--)
736 if(szDestPath[i] != _T('\\'))
737 szDestPath[i] = _T('\0');
738 else
739 break;
740
741 do
742 {
743 /* Check Breaker */
744 if(CheckCtrlBreak(BREAK_INPUT))
745 {
746 freep(arg);
747 return 1;
748 }
749 /* Set the override to yes each new file */
750 nOverwrite = 1;
751
752 /* If it couldnt open the file handle, print out the error */
753 if(hFile == INVALID_HANDLE_VALUE)
754 {
755 ConOutFormatMessage (GetLastError(), szSrcPath);
756 freep (arg);
757 nErrorLevel = 1;
758 return 1;
759 }
760
761 /* Ignore the . and .. files */
762 if(!_tcscmp (findBuffer.cFileName, _T(".")) ||
763 !_tcscmp (findBuffer.cFileName, _T(".."))||
764 findBuffer.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
765 continue;
766
767 /* Copy the base folder over to a tmp string */
768 _tcscpy(tmpDestPath,szDestPath);
769
770 /* Can't put a file into a folder that isnt there */
771 if(!IsExistingDirectory(szDestPath))
772 {
773 ConOutFormatMessage (GetLastError (), szSrcPath);
774 freep (arg);
775 nErrorLevel = 1;
776 return 1;
777 }
778 /* Copy over the destination path name */
779 if(bSrcName)
780 _tcscat (tmpDestPath, findBuffer.cFileName);
781 else
782 {
783 /* If there is no wildcard you can use the name the user entered */
784 if(_tcschr (PreserveName, _T('*')) == NULL)
785 {
786 _tcscat (tmpDestPath, PreserveName);
787 }
788 else
789 {
790 /* The following lines of copy were written by someone else
791 (most likely Eric Khoul) and it was taken from ren.c */
792 LPTSTR p,q,r;
793 TCHAR DoneFile[MAX_PATH];
794 /* build destination file name */
795 p = findBuffer.cFileName;
796 q = PreserveName;
797 r = DoneFile;
798 while(*q != 0)
799 {
800 if (*q == '*')
801 {
802 q++;
803 while (*p != 0 && *p != *q)
804 {
805 *r = *p;
806 p++;
807 r++;
808 }
809 }
810 else if (*q == '?')
811 {
812 q++;
813 if (*p != 0)
814 {
815 *r = *p;
816 p++;
817 r++;
818 }
819 }
820 else
821 {
822 *r = *q;
823 if (*p != 0)
824 p++;
825 q++;
826 r++;
827 }
828 }
829 *r = 0;
830 /* Add the filename to the tmp string path */
831 _tcscat (tmpDestPath, DoneFile);
832
833 }
834 }
835
836
837 /* Build the string path to the source file */
838 _tcscpy(tmpSrcPath,szSrcPath);
839 _tcscat (tmpSrcPath, findBuffer.cFileName);
840
841 /* Check to see if the file is the same file */
842 if(!bTouch && !_tcscmp (tmpSrcPath, tmpDestPath))
843 continue;
844
845 /* Handle any overriding / prompting that needs to be done */
846 if(((!(dwFlags & COPY_NO_PROMPT) && IsExistingFile (tmpDestPath)) || dwFlags & COPY_PROMPT) && !bTouch)
847 nOverwrite = CopyOverwrite(tmpDestPath);
848 if(nOverwrite == PROMPT_NO || nOverwrite == PROMPT_BREAK)
849 continue;
850 if(nOverwrite == PROMPT_ALL || (nOverwrite == PROMPT_YES && bAppend))
851 dwFlags |= COPY_NO_PROMPT;
852
853 /* Tell weather the copy was successful or not */
854 if(copy(tmpSrcPath,tmpDestPath, bAppend, dwFlags, bTouch))
855 {
856 nFiles++;
857 /* only print source name when more then one file */
858 if(_tcschr (arg[nSrc], _T('+')) != NULL || _tcschr (arg[nSrc], _T('*')) != NULL)
859 ConOutPrintf(_T("%s\n"),findBuffer.cFileName);
860 //LoadString(CMD_ModuleHandle, STRING_MOVE_ERROR1, szMsg, RC_STRING_MAX_SIZE);
861 }
862 else
863 {
864 /* print out the error message */
865 LoadString(CMD_ModuleHandle, STRING_COPY_ERROR3, szMsg, RC_STRING_MAX_SIZE);
866 ConOutPrintf(szMsg);
867 ConOutFormatMessage (GetLastError(), szSrcPath);
868 nErrorLevel = 1;
869 }
870
871 /* Loop through all wildcard files */
872 }while(FindNextFile (hFile, &findBuffer));
873 /* Loop through all files in src string with a + */
874 }while(!bDone);
875
876 /* print out the number of files copied */
877 LoadString(CMD_ModuleHandle, STRING_COPY_FILE, szMsg, RC_STRING_MAX_SIZE);
878 ConOutPrintf(szMsg, nFiles);
879
880 CloseHandle(hFile);
881 if (arg!=NULL)
882 free(arg);
883
884 return 0;
885 }
886
887
888 #endif /* INCLUDE_CMD_COPY */