Made cmd unicode compatible.
[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 if(nFiles < 1)
541 {
542 /* There is not enough files, there has to be at least 1 */
543 ConOutResPuts(STRING_ERROR_REQ_PARAM_MISSING);
544 freep (arg);
545 return 1;
546 }
547
548 if(nFiles > 2)
549 {
550 /* there is too many file names in command */
551 LoadString(CMD_ModuleHandle, STRING_ERROR_TOO_MANY_PARAMETERS, szMsg, RC_STRING_MAX_SIZE);
552 ConErrPrintf(szMsg,_T(""));
553 nErrorLevel = 1;
554 freep (arg);
555 return 1;
556 }
557
558 if(((_tcschr (arg[nSrc], _T('+')) != NULL) ||
559 (_tcschr (arg[nSrc], _T('*')) != NULL && _tcschr (arg[nDes], _T('*')) == NULL) ||
560 (IsExistingDirectory (arg[nSrc]) && (_tcschr (arg[nDes], _T('*')) == NULL && !IsExistingDirectory (arg[nDes])))
561 ))
562 {
563 /* There is a + in the source filename, this means
564 that there is more then one file being put into
565 one file. */
566 bAppend = TRUE;
567 if(_tcschr (arg[nSrc], _T('+')) != NULL)
568 appendPointer = arg[nSrc];
569 }
570
571 /* Reusing the number of files variable */
572 nFiles = 0;
573
574 do
575 {
576 /* Set up the string that is the path to the destination */
577 if(nDes != -1)
578 {
579 if(_tcslen(arg[nDes]) == 2 && arg[nDes][1] == _T(':'))
580 {
581 GetRootPath(arg[nDes],szDestPath,MAX_PATH);
582 }
583 else
584 /* If the user entered two file names then form the full string path*/
585 GetFullPathName (arg[nDes], MAX_PATH, szDestPath, NULL);
586
587 }
588 else
589 {
590 /* If no destination was entered then just use
591 the current directory as the destination */
592 GetCurrentDirectory (MAX_PATH, szDestPath);
593 }
594
595
596 /* Get the full string of the path to the source file*/
597 if(_tcschr (arg[nSrc], _T('+')) != NULL)
598 {
599 _tcscpy(tmpName,_T("\0"));
600 /* Loop through the source file name and copy all
601 the chars one at a time until it gets too + */
602 while(TRUE)
603 {
604 if(!_tcsncmp (appendPointer,_T("+"),1) || !_tcsncmp (appendPointer,_T("\0"),1))
605 {
606 /* Now that the pointer is on the + we
607 need to go to the start of the next filename */
608 if(!_tcsncmp (appendPointer,_T("+"),1))
609 appendPointer++;
610 else
611 bDone = TRUE;
612 break;
613
614 }
615
616 _tcsncat(tmpName,appendPointer,1);
617 appendPointer++;
618
619 }
620 /* Finish the string off with a null char */
621 _tcsncat(tmpName,_T("\0"),1);
622
623 if(_tcschr (arg[nSrc], _T(',')) != NULL)
624 {
625 /* Only time there is a , in the source is when they are using touch
626 Cant have a destination and can only have on ,, at the end of the string
627 Cant have more then one file name */
628 szTouch = _tcsstr (arg[nSrc], _T("+"));
629 if(_tcsncmp (szTouch,_T("+,,\0"),4) || nDes != -1)
630 {
631 LoadString(CMD_ModuleHandle, STRING_ERROR_INVALID_PARAM_FORMAT, szMsg, RC_STRING_MAX_SIZE);
632 ConErrPrintf(szMsg,arg[nSrc]);
633 nErrorLevel = 1;
634 freep (arg);
635 return 1;
636 }
637 bTouch = TRUE;
638 bDone = TRUE;
639 }
640
641 if(_tcslen(tmpName) == 2)
642 {
643 if(tmpName[1] == _T(':'))
644 {
645
646 GetRootPath(tmpName,szSrcPath,MAX_PATH);
647 }
648 }
649 else
650 /* Get the full path to first file in the string of file names */
651 GetFullPathName (tmpName, MAX_PATH, szSrcPath, NULL);
652 }
653 else
654 {
655 bDone = TRUE;
656 if(_tcslen(arg[nSrc]) == 2 && arg[nSrc][1] == _T(':'))
657 {
658 GetRootPath(arg[nSrc],szSrcPath,MAX_PATH);
659 }
660 else
661 /* Get the full path of the source file */
662 GetFullPathName (arg[nSrc], MAX_PATH, szSrcPath, NULL);
663
664 }
665
666 /* From this point on, we can assume that the shortest path is 3 letters long
667 and that would be [DriveLetter]:\ */
668
669 /* If there is no * in the path name and it is a folder
670 then we will need to add a wildcard to the pathname
671 so FindFirstFile comes up with all the files in that
672 folder */
673 if(_tcschr (szSrcPath, _T('*')) == NULL &&
674 IsExistingDirectory (szSrcPath))
675 {
676 /* If it doesnt have a \ at the end already then on needs to be added */
677 if(szSrcPath[_tcslen(szSrcPath) - 1] != _T('\\'))
678 _tcscat (szSrcPath, _T("\\"));
679 /* Add a wildcard after the \ */
680 _tcscat (szSrcPath, _T("*"));
681 }
682 /* Make sure there is an ending slash to the path if the dest is a folder */
683 if(_tcschr (szDestPath, _T('*')) == NULL &&
684 IsExistingDirectory(szDestPath))
685 {
686 if(szDestPath[_tcslen(szDestPath) - 1] != _T('\\'))
687 _tcscat (szDestPath, _T("\\"));
688 }
689
690
691 /* Get a list of all the files */
692 hFile = FindFirstFile (szSrcPath, &findBuffer);
693
694
695 /* We need to figure out what the name of the file in the is going to be */
696 if((szDestPath[_tcslen(szDestPath) - 1] == _T('*') && szDestPath[_tcslen(szDestPath) - 2] == _T('\\')) ||
697 szDestPath[_tcslen(szDestPath) - 1] == _T('\\'))
698 {
699 /* In this case we will be using the same name as the source file
700 for the destination file because destination is a folder */
701 bSrcName = TRUE;
702 }
703 else
704 {
705 /* Save the name the user entered */
706 UseThisName = _tcsrchr(szDestPath,_T('\\'));
707 UseThisName++;
708 _tcscpy(PreserveName,UseThisName);
709 }
710
711 /* Strip the paths back to the folder they are in */
712 for(i = (_tcslen(szSrcPath) - 1); i > -1; i--)
713 if(szSrcPath[i] != _T('\\'))
714 szSrcPath[i] = _T('\0');
715 else
716 break;
717
718 for(i = (_tcslen(szDestPath) - 1); i > -1; i--)
719 if(szDestPath[i] != _T('\\'))
720 szDestPath[i] = _T('\0');
721 else
722 break;
723
724 do
725 {
726 /* Set the override to yes each new file */
727 nOverwrite = 1;
728
729 /* If it couldnt open the file handle, print out the error */
730 if(hFile == INVALID_HANDLE_VALUE)
731 {
732 ConOutFormatMessage (GetLastError(), szSrcPath);
733 freep (arg);
734 nErrorLevel = 1;
735 return 1;
736 }
737
738 /* Ignore the . and .. files */
739 if(!_tcscmp (findBuffer.cFileName, _T(".")) ||
740 !_tcscmp (findBuffer.cFileName, _T(".."))||
741 findBuffer.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
742 continue;
743
744 /* Copy the base folder over to a tmp string */
745 _tcscpy(tmpDestPath,szDestPath);
746
747 /* Can't put a file into a folder that isnt there */
748 if(!IsExistingDirectory(szDestPath))
749 {
750 ConOutFormatMessage (GetLastError (), szSrcPath);
751 freep (arg);
752 nErrorLevel = 1;
753 return 1;
754 }
755 /* Copy over the destination path name */
756 if(bSrcName)
757 _tcscat (tmpDestPath, findBuffer.cFileName);
758 else
759 {
760 /* If there is no wildcard you can use the name the user entered */
761 if(_tcschr (PreserveName, _T('*')) == NULL)
762 {
763 _tcscat (tmpDestPath, PreserveName);
764 }
765 else
766 {
767 /* The following lines of copy were written by someone else
768 (most likely Eric Khoul) and it was taken from ren.c */
769 LPTSTR p,q,r;
770 TCHAR DoneFile[MAX_PATH];
771 /* build destination file name */
772 p = findBuffer.cFileName;
773 q = PreserveName;
774 r = DoneFile;
775 while(*q != 0)
776 {
777 if (*q == '*')
778 {
779 q++;
780 while (*p != 0 && *p != *q)
781 {
782 *r = *p;
783 p++;
784 r++;
785 }
786 }
787 else if (*q == '?')
788 {
789 q++;
790 if (*p != 0)
791 {
792 *r = *p;
793 p++;
794 r++;
795 }
796 }
797 else
798 {
799 *r = *q;
800 if (*p != 0)
801 p++;
802 q++;
803 r++;
804 }
805 }
806 *r = 0;
807 /* Add the filename to the tmp string path */
808 _tcscat (tmpDestPath, DoneFile);
809
810 }
811 }
812
813
814 /* Build the string path to the source file */
815 _tcscpy(tmpSrcPath,szSrcPath);
816 _tcscat (tmpSrcPath, findBuffer.cFileName);
817
818 /* Check to see if the file is the same file */
819 if(!bTouch && !_tcscmp (tmpSrcPath, tmpDestPath))
820 continue;
821
822 /* Handle any overriding / prompting that needs to be done */
823 if(((!(dwFlags & COPY_NO_PROMPT) && IsExistingFile (tmpDestPath)) || dwFlags & COPY_PROMPT) && !bTouch)
824 nOverwrite = Overwrite(tmpDestPath);
825 if(nOverwrite == PROMPT_NO || nOverwrite == PROMPT_BREAK)
826 continue;
827 if(nOverwrite == PROMPT_ALL || (nOverwrite == PROMPT_YES && bAppend))
828 dwFlags |= COPY_NO_PROMPT;
829
830 /* Tell weather the copy was successful or not */
831 if(copy(tmpSrcPath,tmpDestPath, bAppend, dwFlags, bTouch))
832 {
833 nFiles++;
834 /* only print source name when more then one file */
835 if(_tcschr (arg[nSrc], _T('+')) != NULL || _tcschr (arg[nSrc], _T('*')) != NULL)
836 ConOutPrintf(_T("%s\n"),findBuffer.cFileName);
837 //LoadString(CMD_ModuleHandle, STRING_MOVE_ERROR1, szMsg, RC_STRING_MAX_SIZE);
838 }
839 else
840 {
841 /* print out the error message */
842 LoadString(CMD_ModuleHandle, STRING_COPY_ERROR3, szMsg, RC_STRING_MAX_SIZE);
843 ConOutPrintf(szMsg);
844 ConOutFormatMessage (GetLastError(), szSrcPath);
845 nErrorLevel = 1;
846 }
847
848 /* Loop through all wildcard files */
849 }while(FindNextFile (hFile, &findBuffer));
850 /* Loop through all files in src string with a + */
851 }while(!bDone);
852
853 /* print out the number of files copied */
854 LoadString(CMD_ModuleHandle, STRING_COPY_FILE, szMsg, RC_STRING_MAX_SIZE);
855 ConOutPrintf(szMsg, nFiles);
856
857 CloseHandle(hFile);
858 if (arg!=NULL)
859 free(arg);
860
861 return 0;
862 }
863
864
865 #endif /* INCLUDE_CMD_COPY */