1 /* $Id: copy.c,v 1.6 2004/11/08 02:16:06 weiden Exp $
3 * COPY.C -- copy internal command.
8 * 01-Aug-98 (Rob Lake z63rrl@morgan.ucs.mun.ca)
11 * 13-Aug-1998 (John P. Price)
12 * fixed memory leak problem in copy function.
13 * fixed copy function so it would work with wildcards in the source
15 * 13-Dec-1998 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
16 * Added COPY command to CMD.
18 * 26-Jan-1998 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
19 * Replaced CRT io functions by Win32 io functions.
21 * 27-Oct-1998 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
22 * Disabled prompting when used in batch mode.
27 #ifdef INCLUDE_CMD_COPY
30 #define VERIFY 1 /* VERIFY Switch */
31 #define BINARY 2 /* File is to be copied as BINARY */
32 #define ASCII 4 /* File is to be copied as ASCII */
33 #define PROMPT 8 /* Prompt before overwriting files */
34 #define NPROMPT 16 /* Do not prompt before overwriting files */
35 #define HELP 32 /* Help was asked for */
36 #define SOURCE 128 /* File is a source */
39 typedef struct tagFILES
41 struct tagFILES
*next
;
42 TCHAR szFile
[MAX_PATH
];
43 DWORD dwFlag
; /* BINARY -xor- ASCII */
47 static BOOL
DoSwitches (LPTSTR
, LPDWORD
);
48 static BOOL
AddFile (LPFILES
, TCHAR
*, int *, int *, LPDWORD
);
49 static BOOL
AddFiles (LPFILES
, TCHAR
*, int *, int *, int *, LPDWORD
);
50 static BOOL
GetDestination (LPFILES
, LPFILES
);
51 static INT
ParseCommand (LPFILES
, int, TCHAR
**, LPDWORD
);
52 static VOID
DeleteFileList (LPFILES
);
53 static INT
Overwrite (LPTSTR
);
58 IsDirectory (LPTSTR fn
)
60 if (!IsValidFileName (fn
))
62 return (GetFileAttributes (fn
) & FILE_ATTRIBUTE_DIRECTORY
);
67 DoSwitches (LPTSTR arg
, LPDWORD lpdwFlags
)
69 if (!_tcsicmp (arg
, _T("/-Y")))
72 *lpdwFlags
&= ~NPROMPT
;
75 else if (_tcslen (arg
) > 2)
77 error_too_many_parameters (_T(""));
81 switch (_totupper (arg
[1]))
89 *lpdwFlags
&= ~BINARY
;
98 *lpdwFlags
&= ~PROMPT
;
99 *lpdwFlags
|= NPROMPT
;
103 error_invalid_switch (arg
[1]);
111 AddFile (LPFILES f
, TCHAR
*arg
, int *source
, int *dest
, LPDWORD flags
)
115 error_too_many_parameters (_T(""));
128 _tcscpy(f
->szFile
, arg
);
129 f
->dwFlag
|= *flags
& ASCII
? ASCII
: BINARY
;
130 if ((f
->next
= (LPFILES
)malloc (sizeof (FILES
))) == NULL
)
132 error_out_of_memory ();
143 AddFiles (LPFILES f
, TCHAR
*arg
, int *source
, int *dest
,
144 int *count
, LPDWORD flags
)
152 error_too_many_parameters (_T(""));
159 while (arg
[j
] == _T('+'))
162 while (arg
[j
] != _T('\0'))
165 if (t
[k
] == '+' || arg
[j
] == _T('\0'))
169 if (arg
[j
] == _T('\0') && t
[k
] != _T('+'))
173 _tcscpy (f
->szFile
, t
);
176 f
->dwFlag
|= *flags
| SOURCE
| ASCII
;
178 f
->dwFlag
|= *flags
| BINARY
| SOURCE
;
180 if ((f
->next
= (LPFILES
)malloc (sizeof (FILES
))) == NULL
)
182 error_out_of_memory ();
194 if (arg
[--j
] == _T('+'))
202 GetDestination (LPFILES f
, LPFILES dest
)
207 while (f
->next
!= NULL
)
215 if ((f
->dwFlag
& SOURCE
) == 0)
219 _tcscpy (dest
->szFile
, f
->szFile
);
220 dest
->dwFlag
= f
->dwFlag
;
231 ParseCommand (LPFILES f
, int argc
, TCHAR
**arg
, LPDWORD lpdwFlags
)
242 for (i
= 0; i
< argc
; i
++)
244 if (arg
[i
][0] == _T('/'))
246 if (!DoSwitches (arg
[i
], lpdwFlags
))
251 if (!_tcscmp(arg
[i
], _T("+")))
253 else if (!_tcschr(arg
[i
], _T('+')) && source
)
256 // Make sure we have a clean workable path
258 GetFullPathName( arg
[i
], 128, (LPTSTR
) &temp
, NULL
);
259 // printf("A Input %s, Output %s\n", arg[i], temp);
261 if (!AddFile(f
, (TCHAR
*) &temp
, &source
, &dest
, lpdwFlags
))
269 GetFullPathName( arg
[i
], 128, (LPTSTR
) &temp
, NULL
);
270 // printf("B Input %s, Output %s\n", arg[i], temp);
272 if (!AddFiles(f
, (TCHAR
*) &temp
, &source
, &dest
, &count
, lpdwFlags
))
274 while (f
->next
!= NULL
)
281 DebugPrintf (_T("ParseCommand: flags has %s\n"),
282 *lpdwFlags
& ASCII
? _T("ASCII") : _T("BINARY"));
289 DeleteFileList (LPFILES f
)
303 Overwrite (LPTSTR fn
)
308 ConOutPrintf (_T("Overwrite %s (Yes/No/All)? "), fn
);
309 ConInString (inp
, 10);
313 for (p
= inp
; _istspace (*p
); p
++)
316 if (*p
!= _T('Y') && *p
!= _T('A'))
325 #define BUFF_SIZE 16384 /* 16k = max buffer size */
328 int copy (LPTSTR source
, LPTSTR dest
, int append
, LPDWORD lpdwFlags
)
341 DebugPrintf (_T("checking mode\n"));
344 dwAttrib
= GetFileAttributes (source
);
346 hFileSrc
= CreateFile (source
, GENERIC_READ
, FILE_SHARE_READ
,
347 NULL
, OPEN_EXISTING
, 0, NULL
);
348 if (hFileSrc
== INVALID_HANDLE_VALUE
)
350 ConErrPrintf (_T("Error: Cannot open source - %s!\n"), source
);
355 DebugPrintf (_T("getting time\n"));
358 GetFileTime (hFileSrc
, &srctime
, NULL
, NULL
);
361 DebugPrintf (_T("copy: flags has %s\n"),
362 *lpdwFlags
& ASCII
? "ASCII" : "BINARY");
365 if (!IsValidFileName (dest
))
368 DebugPrintf (_T("opening/creating\n"));
371 CreateFile (dest
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, NULL
);
375 if (!_tcscmp (dest
, source
))
377 ConErrPrintf (_T("Error: Can't copy onto itself!\n"));
378 CloseHandle (hFileSrc
);
383 DebugPrintf (_T("SetFileAttributes (%s, FILE_ATTRIBUTE_NORMAL);\n"), dest
);
385 SetFileAttributes (dest
, FILE_ATTRIBUTE_NORMAL
);
388 DebugPrintf (_T("DeleteFile (%s);\n"), dest
);
393 CreateFile (dest
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, NULL
);
397 LONG lFilePosHigh
= 0;
399 if (!_tcscmp (dest
, source
))
401 CloseHandle (hFileSrc
);
406 DebugPrintf (_T("opening/appending\n"));
409 CreateFile (dest
, GENERIC_WRITE
, 0, NULL
, OPEN_EXISTING
, 0, NULL
);
410 SetFilePointer (hFileDest
, 0, &lFilePosHigh
,FILE_END
);
413 if (hFileDest
== INVALID_HANDLE_VALUE
)
415 CloseHandle (hFileSrc
);
416 error_path_not_found ();
420 buffer
= (LPBYTE
)malloc (BUFF_SIZE
);
423 CloseHandle (hFileDest
);
424 CloseHandle (hFileSrc
);
425 error_out_of_memory ();
431 ReadFile (hFileSrc
, buffer
, BUFF_SIZE
, &dwRead
, NULL
);
432 if (*lpdwFlags
& ASCII
)
434 for (i
= 0; i
< dwRead
; i
++)
436 if (((LPTSTR
)buffer
)[i
] == 0x1A)
448 WriteFile (hFileDest
, buffer
, dwRead
, &dwWritten
, NULL
);
449 if (dwWritten
!= dwRead
)
451 ConErrPrintf (_T("Error writing destination!\n"));
453 CloseHandle (hFileDest
);
454 CloseHandle (hFileSrc
);
458 while (dwRead
&& !bEof
);
461 DebugPrintf (_T("setting time\n"));
463 SetFileTime (hFileDest
, &srctime
, NULL
, NULL
);
465 if (*lpdwFlags
& ASCII
)
467 ((LPTSTR
)buffer
)[0] = 0x1A;
468 ((LPTSTR
)buffer
)[1] = _T('\0');
470 DebugPrintf (_T("appending ^Z\n"));
472 WriteFile (hFileDest
, buffer
, sizeof(TCHAR
), &dwWritten
, NULL
);
476 CloseHandle (hFileDest
);
477 CloseHandle (hFileSrc
);
480 DebugPrintf (_T("setting mode\n"));
482 SetFileAttributes (dest
, dwAttrib
);
489 SetupCopy (LPFILES sources
, TCHAR
**p
, BOOL bMultiple
,
490 TCHAR
*drive_d
, TCHAR
*dir_d
, TCHAR
*file_d
,
491 TCHAR
*ext_d
, int *append
, LPDWORD lpdwFlags
)
493 WIN32_FIND_DATA find
;
494 TCHAR drive_s
[_MAX_DRIVE
];
495 TCHAR dir_s
[_MAX_DIR
];
496 TCHAR file_s
[_MAX_FNAME
];
497 TCHAR ext_s
[_MAX_EXT
];
498 TCHAR from_merge
[_MAX_PATH
];
510 DebugPrintf (_T("SetupCopy\n"));
513 real_source
= (LPTSTR
)malloc (MAX_PATH
* sizeof(TCHAR
));
514 real_dest
= (LPTSTR
)malloc (MAX_PATH
* sizeof(TCHAR
));
516 if (!real_source
|| !real_dest
)
518 error_out_of_memory ();
519 DeleteFileList (sources
);
526 while (sources
->next
!= NULL
)
529 /* Force a clean full path
531 GetFullPathName( sources
->szFile
, 128, (LPTSTR
) &temp
, NULL
);
533 _tsplitpath (sources
->szFile
, drive_s
, dir_s
, file_s
, ext_s
);
535 hFind
= FindFirstFile ((TCHAR
*)&temp
, &find
);
536 if (hFind
== INVALID_HANDLE_VALUE
)
538 error_file_not_found();
547 if (find
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
550 _tmakepath(from_merge
, drive_d
, dir_d
, file_d
, ext_d
);
552 if (from_merge
[_tcslen(from_merge
) - 1] == _T('\\'))
553 from_merge
[_tcslen(from_merge
) - 1] = 0;
555 // printf("Merge %s, filename %s\n", from_merge, find.cFileName);
557 if (IsDirectory (from_merge
))
560 // printf("Merge DIR\n");
563 _tcscat (from_merge
, _T("\\"));
564 _tcscat (from_merge
, find
.cFileName
);
569 _tcscpy (real_dest
, from_merge
);
570 _tmakepath (real_source
, drive_s
, dir_s
, find
.cFileName
, NULL
);
573 DebugPrintf(_T("copying %S -> %S (%Sappending%S)\n"),
574 real_source
, real_dest
,
575 *append
? _T("") : _T("not "),
576 sources
->dwFlag
& ASCII
? _T(", ASCII") : _T(", BINARY"));
579 if (IsValidFileName (real_dest
) && !bAll
)
581 /* Don't prompt in a batch file */
590 over
= Overwrite (real_dest
);
599 if (copy (real_source
, real_dest
, *append
, lpdwFlags
))
602 bDone
= FindNextFile (hFind
, &find
);
610 sources
= sources
->next
;
620 INT
cmd_copy (LPTSTR first
, LPTSTR rest
)
623 TCHAR drive_d
[_MAX_DRIVE
];
624 TCHAR dir_d
[_MAX_DIR
];
625 TCHAR file_d
[_MAX_FNAME
];
626 TCHAR ext_d
[_MAX_EXT
];
633 LPFILES sources
= NULL
;
634 LPFILES start
= NULL
;
641 if (!_tcsncmp (rest
, _T("/?"), 2))
643 ConOutPuts (_T("Copies one or more files to another location.\n"
645 "COPY [/V][/Y|/-Y][/A|/B] source [/A|/B]\n"
646 " [+ source [/A|/B] [+ ...]] [destination [/A|/B]]\n"
648 " source Specifies the file or files to be copied.\n"
649 " /A Indicates an ASCII text file.\n"
650 " /B Indicates a binary file.\n"
651 " destination Specifies the directory and/or filename for the new file(s).\n"
652 " /V Verifies that new files are written correctly.\n"
653 " /Y Suppresses prompting to confirm you want to overwrite an\n"
654 " existing destination file.\n"
655 " /-Y Causes prompting to confirm you want to overwrite an\n"
656 " existing destination file.\n"
658 "The switch /Y may be present in the COPYCMD environment variable.\n"
663 p
= split (rest
, &argc
, FALSE
);
667 error_req_param_missing ();
671 sources
= (LPFILES
)malloc (sizeof (FILES
));
674 error_out_of_memory ();
677 sources
->next
= NULL
;
680 if ((files
= ParseCommand (sources
, argc
, p
, &dwFlags
)) == -1)
682 DeleteFileList (sources
);
688 error_req_param_missing();
689 DeleteFileList (sources
);
695 bDestFound
= GetDestination (sources
, &dest
);
698 _tsplitpath (dest
.szFile
, drive_d
, dir_d
, file_d
, ext_d
);
699 if (IsDirectory (dest
.szFile
))
701 // printf("A szFile= %s, Dir = %s, File = %s, Ext = %s\n", dest.szFile, dir_d, file_d, ext_d);
702 _tcscat (dir_d
, file_d
);
703 _tcscat (dir_d
, ext_d
);
704 file_d
[0] = _T('\0');
709 if (_tcschr (dest
.szFile
, _T('*')) || _tcschr (dest
.szFile
, _T('?')))
714 if (_tcschr(rest
, _T('+')))
722 if (bDestFound
&& !bWildcards
)
725 // _tcscpy(sources->szFile, dest.szFile);
727 copied
= SetupCopy (sources
, p
, bMultiple
, drive_d
, dir_d
, file_d
, ext_d
, &append
, &dwFlags
);
729 else if (bDestFound
&& bWildcards
)
731 ConErrPrintf (_T("Error: Not implemented yet!\n"));
732 DeleteFileList (sources
);
736 else if (!bDestFound
&& !bMultiple
)
738 _tsplitpath (sources
->szFile
, drive_d
, dir_d
, file_d
, ext_d
);
739 if (IsDirectory (sources
->szFile
))
741 // printf("B File = %s, Ext = %s\n", file_d, ext_d);
743 _tcscat (dir_d
, file_d
);
744 _tcscat (dir_d
, ext_d
);
745 file_d
[0] = _T('\0');
748 copied
= SetupCopy (sources
, p
, FALSE
, _T(""), _T(""), file_d
, ext_d
, &append
, &dwFlags
);
752 _tsplitpath(sources
->szFile
, drive_d
, dir_d
, file_d
, ext_d
);
753 if (IsDirectory (sources
->szFile
))
755 // printf("C File = %s, Ext = %s\n", file_d, ext_d);
757 _tcscat (dir_d
, file_d
);
758 _tcscat (dir_d
, ext_d
);
759 file_d
[0] = _T('\0');
763 ConOutPuts (sources
->szFile
);
765 copied
= SetupCopy (sources
->next
, p
, bMultiple
, drive_d
, dir_d
, file_d
, ext_d
, &append
, &dwFlags
) + 1;
768 DeleteFileList (sources
);
770 ConOutPrintf (_T(" %d file(s) copied\n"), copied
);
774 #endif /* INCLUDE_CMD_COPY */