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