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