16b561727d0de8ec932c2644e89b8eb1052f5ac8
2 * COPY.C -- copy internal command.
7 * 01-Aug-98 (Rob Lake z63rrl@morgan.ucs.mun.ca)
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
14 * 13-Dec-1998 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
15 * Added COPY command to CMD.
17 * 26-Jan-1998 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
18 * Replaced CRT io functions by Win32 io functions.
21 #define WIN32_LEAN_AND_MEAN
25 #ifdef INCLUDE_CMD_COPY
36 #define VERIFY 1 /* VERIFY Switch */
37 #define BINARY 2 /* File is to be copied as BINARY */
38 #define ASCII 4 /* File is to be copied as ASCII */
39 #define PROMPT 8 /* Prompt before overwriting files */
40 #define NPROMPT 16 /* Do not prompt before overwriting files */
41 #define HELP 32 /* Help was asked for */
42 #define SOURCE 128 /* File is a source */
45 typedef struct tagFILES
47 struct tagFILES
*next
;
48 TCHAR szFile
[MAX_PATH
];
49 DWORD dwFlag
; /* BINARY -xor- ASCII */
53 static BOOL
DoSwitches (LPTSTR
, LPDWORD
);
54 static BOOL
AddFile (LPFILES
, char *, int *, int *, unsigned *);
55 static BOOL
AddFiles (LPFILES
, char *, int *, int *, int *, unsigned *);
56 static BOOL
GetDestination (LPFILES
, LPFILES
);
57 static INT
ParseCommand (LPFILES
, int, char **, LPDWORD
);
58 static VOID
DeleteFileList (LPFILES
);
59 static INT
Overwrite (LPTSTR
);
63 static BOOL
IsDirectory (LPTSTR fn
)
65 if (!IsValidFileName (fn
))
67 return (GetFileAttributes (fn
) & FILE_ATTRIBUTE_DIRECTORY
);
71 static BOOL
DoSwitches (LPTSTR arg
, LPDWORD lpdwFlags
)
73 if (!_tcsicmp (arg
, _T("/-Y")))
76 *lpdwFlags
&= ~NPROMPT
;
79 else if (_tcslen (arg
) > 2)
81 error_too_many_parameters ("");
85 switch (_totupper (arg
[1]))
93 *lpdwFlags
&= ~BINARY
;
102 *lpdwFlags
&= ~PROMPT
;
103 *lpdwFlags
|= NPROMPT
;
107 error_invalid_switch (arg
[1]);
115 AddFile (LPFILES f
, char *arg
, int *source
, int *dest
, unsigned *flags
)
119 error_too_many_parameters ("");
132 _tcscpy(f
->szFile
, arg
);
133 f
->dwFlag
|= *flags
& ASCII
? ASCII
: BINARY
;
134 if ((f
->next
= (LPFILES
)malloc (sizeof (FILES
))) == NULL
)
136 error_out_of_memory ();
147 AddFiles (LPFILES f
, char *arg
, int *source
, int *dest
,
148 int *count
, unsigned *flags
)
156 error_too_many_parameters ("");
163 while (arg
[j
] == _T('+'))
166 while (arg
[j
] != _T('\0'))
169 if (t
[k
] == '+' || arg
[j
] == _T('\0'))
173 if (arg
[j
] == _T('\0') && t
[k
] != _T('+'))
177 _tcscpy (f
->szFile
, t
);
180 f
->dwFlag
|= *flags
| SOURCE
| ASCII
;
182 f
->dwFlag
|= *flags
| BINARY
| SOURCE
;
184 if ((f
->next
= (LPFILES
)malloc (sizeof (FILES
))) == NULL
)
186 error_out_of_memory ();
198 if (arg
[--j
] == _T('+'))
205 static BOOL
GetDestination (LPFILES f
, LPFILES dest
)
210 while (f
->next
!= NULL
)
218 if ((f
->dwFlag
& SOURCE
) == 0)
222 _tcscpy (dest
->szFile
, f
->szFile
);
223 dest
->dwFlag
= f
->dwFlag
;
234 ParseCommand (LPFILES f
, int argc
, char **arg
, LPDWORD lpdwFlags
)
245 for (i
= 0; i
< argc
; i
++)
247 if (arg
[i
][0] == _T('/'))
249 if (!DoSwitches (arg
[i
], lpdwFlags
))
254 if (!_tcscmp(arg
[i
], _T("+")))
256 else if (!_tcschr(arg
[i
], _T('+')) && source
)
258 if (!AddFile(f
, arg
[i
], &source
, &dest
, lpdwFlags
))
265 if (!AddFiles(f
, arg
[i
], &source
, &dest
, &count
, lpdwFlags
))
267 while (f
->next
!= NULL
)
273 DebugPrintf ("ParseCommand: flags has %s\n",
274 *lpdwFlags
& ASCII
? "ASCII" : "BINARY");
280 static VOID
DeleteFileList (LPFILES f
)
294 Overwrite (LPTSTR fn
)
299 ConOutPrintf (_T("Overwrite %s (Yes/No/All)? "), fn
);
300 ConInString (inp
, 10);
303 for (p
= inp
; _istspace (*p
); p
++)
306 if (*p
!= _T('Y') && *p
!= _T('A'))
315 #define BUFF_SIZE 16384 /* 16k = max buffer size */
318 int copy (LPTSTR source
, LPTSTR dest
, int append
, LPDWORD lpdwFlags
)
331 DebugPrintf ("checking mode\n");
334 dwAttrib
= GetFileAttributes (source
);
336 hFileSrc
= CreateFile (source
, GENERIC_READ
, FILE_SHARE_READ
,
337 NULL
, OPEN_EXISTING
, 0, NULL
);
338 if (hFileSrc
== INVALID_HANDLE_VALUE
)
340 ConErrPrintf (_T("Error: Cannot open source - %s!\n"), source
);
345 DebugPrintf (_T("getting time\n"));
348 GetFileTime (hFileSrc
, &srctime
, NULL
, NULL
);
351 DebugPrintf (_T("copy: flags has %s\n"),
352 *lpdwFlags
& ASCII
? "ASCII" : "BINARY");
355 if (!IsValidFileName (dest
))
358 DebugPrintf (_T("opening/creating\n"));
361 CreateFile (dest
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, NULL
);
365 if (!_tcscmp (dest
, source
))
367 ConErrPrintf (_T("Error: Can't copy onto itself!\n"));
368 CloseHandle (hFileSrc
);
373 DebugPrintf (_T("SetFileAttributes (%s, FILE_ATTRIBUTE_NORMAL);\n"), dest
);
375 SetFileAttributes (dest
, FILE_ATTRIBUTE_NORMAL
);
378 DebugPrintf (_T("DeleteFile (%s);\n"), dest
);
383 CreateFile (dest
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, NULL
);
387 LONG lFilePosHigh
= 0;
389 if (!_tcscmp (dest
, source
))
391 CloseHandle (hFileSrc
);
396 DebugPrintf (_T("opening/appending\n"));
399 CreateFile (dest
, GENERIC_WRITE
, 0, NULL
, OPEN_EXISTING
, 0, NULL
);
400 SetFilePointer (hFileDest
, 0, &lFilePosHigh
,FILE_END
);
403 if (hFileDest
== INVALID_HANDLE_VALUE
)
405 CloseHandle (hFileSrc
);
406 error_path_not_found ();
410 buffer
= (LPBYTE
)malloc (BUFF_SIZE
);
413 CloseHandle (hFileDest
);
414 CloseHandle (hFileSrc
);
415 error_out_of_memory ();
423 ReadFile (hFileSrc
, buffer
, BUFF_SIZE
, &dwRead
, NULL
);
424 if (*lpdwFlags
& ASCII
)
426 for (i
= 0; i
< dwRead
; i
++)
428 if (((LPTSTR
)buffer
)[i
] == 0x1A)
440 WriteFile (hFileDest
, buffer
, dwRead
, &dwWritten
, NULL
);
441 if (dwWritten
!= dwRead
)
443 ConErrPrintf (_T("Error writing destination!\n"));
445 CloseHandle (hFileDest
);
446 CloseHandle (hFileSrc
);
450 while (dwRead
&& !bEof
);
453 DebugPrintf (_T("setting time\n"));
455 SetFileTime (hFileDest
, &srctime
, NULL
, NULL
);
457 if (*lpdwFlags
& ASCII
)
459 ((LPTSTR
)buffer
)[0] = 0x1A;
460 ((LPTSTR
)buffer
)[1] = _T('\0');
462 DebugPrintf (_T("appending ^Z\n"));
464 WriteFile (hFileDest
, buffer
, sizeof(TCHAR
), &dwWritten
, NULL
);
468 CloseHandle (hFileDest
);
469 CloseHandle (hFileSrc
);
472 DebugPrintf (_T("setting mode\n"));
474 SetFileAttributes (dest
, dwAttrib
);
480 int setup_copy (LPFILES sources
, char **p
, BOOL bMultiple
,
481 char *drive_d
, char *dir_d
, char *file_d
,
482 char *ext_d
, int *append
, LPDWORD lpdwFlags
)
484 WIN32_FIND_DATA find
;
486 char drive_s
[_MAX_DRIVE
],
490 char from_merge
[_MAX_PATH
];
501 real_source
= (LPTSTR
)malloc (MAX_PATH
);
502 real_dest
= (LPTSTR
)malloc (MAX_PATH
);
504 if (!real_source
|| !real_dest
)
506 error_out_of_memory ();
507 DeleteFileList (sources
);
514 while (sources
->next
!= NULL
)
516 _splitpath (sources
->szFile
, drive_s
, dir_s
, file_s
, ext_s
);
517 hFind
= FindFirstFile (sources
->szFile
, &find
);
518 if (hFind
== INVALID_HANDLE_VALUE
)
520 error_file_not_found();
521 DeleteFileList (sources
);
530 if (find
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
533 _makepath(from_merge
, drive_d
, dir_d
, file_d
, ext_d
);
534 if (from_merge
[_tcslen(from_merge
) - 1] == _T('\\'))
535 from_merge
[_tcslen(from_merge
) - 1] = 0;
537 if (IsDirectory (from_merge
))
540 _tcscat (from_merge
, _T("\\"));
541 _tcscat (from_merge
, find
.cFileName
);
546 _tcscpy (real_dest
, from_merge
);
547 _makepath (real_source
, drive_s
, dir_s
, find
.cFileName
, NULL
);
550 DebugPrintf (_T("copying %s -> %s (%sappending%s)\n"),
551 real_source
, real_dest
,
552 *append
? "" : "not ",
553 sources
->dwFlag
& ASCII
? ", ASCII" : ", BINARY");
556 if (IsValidFileName (real_dest
) && !bAll
)
558 int over
= Overwrite (real_dest
);
566 if (copy (real_source
, real_dest
, *append
, lpdwFlags
))
569 bDone
= FindNextFile (hFind
, &find
);
577 sources
= sources
->next
;
587 INT
cmd_copy (LPTSTR first
, LPTSTR rest
)
590 char drive_d
[_MAX_DRIVE
],
608 if (!_tcsncmp (rest
, _T("/?"), 2))
610 ConOutPuts (_T("Copies one or more files to another location.\n"
612 "COPY [/V][/Y|/-Y][/A|/B] source [/A|/B]\n"
613 " [+ source [/A|/B] [+ ...]] [destination [/A|/B]]\n"
615 " source Specifies the file or files to be copied.\n"
616 " /A Indicates an ASCII text file.\n"
617 " /B Indicates a binary file.\n"
618 " destination Specifies the directory and/or filename for the new file(s).\n"
619 " /V Verifies that new files are written correctly.\n"
620 " /Y Suppresses prompting to confirm you want to overwrite an\n"
621 " existing destination file.\n"
622 " /-Y Causes prompting to confirm you want to overwrite an\n"
623 " existing destination file.\n"
625 "The switch /Y may be present in the COPYCMD environment variable.\n"
630 p
= split (rest
, &argc
);
634 error_req_param_missing ();
638 sources
= (LPFILES
)malloc (sizeof (FILES
));
641 error_out_of_memory ();
644 sources
->next
= NULL
;
647 if ((files
= ParseCommand (sources
, argc
, p
, &dwFlags
)) == -1)
649 DeleteFileList (sources
);
655 error_req_param_missing();
656 DeleteFileList (sources
);
662 bDestFound
= GetDestination (sources
, &dest
);
665 _splitpath (dest
.szFile
, drive_d
, dir_d
, file_d
, ext_d
);
666 if (IsDirectory (dest
.szFile
))
668 _tcscat (dir_d
, file_d
);
669 _tcscat (dir_d
, ext_d
);
670 file_d
[0] = _T('\0');
675 if (_tcschr (dest
.szFile
, _T('*')) || _tcschr (dest
.szFile
, _T('?')))
680 if (strchr(rest
, '+'))
688 if (bDestFound
&& !bWildcards
)
690 copied
= setup_copy (sources
, p
, bMultiple
, drive_d
, dir_d
, file_d
, ext_d
, &append
, &dwFlags
);
692 else if (bDestFound
&& bWildcards
)
694 ConErrPrintf (_T("Error: Not implemented yet!\n"));
695 DeleteFileList (sources
);
699 else if (!bDestFound
&& !bMultiple
)
701 _splitpath (sources
->szFile
, drive_d
, dir_d
, file_d
, ext_d
);
702 if (IsDirectory (sources
->szFile
))
704 _tcscat (dir_d
, file_d
);
705 _tcscat (dir_d
, ext_d
);
706 file_d
[0] = _T('\0');
709 copied
= setup_copy (sources
, p
, FALSE
, "", "", file_d
, ext_d
, &append
, &dwFlags
);
713 _splitpath(sources
->szFile
, drive_d
, dir_d
, file_d
, ext_d
);
714 if (IsDirectory (sources
->szFile
))
716 _tcscat (dir_d
, file_d
);
717 _tcscat (dir_d
, ext_d
);
718 file_d
[0] = _T('\0');
722 ConOutPuts (sources
->szFile
);
724 copied
= setup_copy (sources
->next
, p
, bMultiple
, drive_d
, dir_d
, file_d
, ext_d
, &append
, &dwFlags
) + 1;
727 DeleteFileList (start
);
729 ConOutPrintf (_T(" %d file(s) copied\n"), copied
);
733 #endif /* INCLUDE_CMD_COPY */