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