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
39 #define VERIFY 1 /* VERIFY Switch */
40 #define BINARY 2 /* File is to be copied as BINARY */
41 #define ASCII 4 /* File is to be copied as ASCII */
42 #define PROMPT 8 /* Prompt before overwriting files */
43 #define NPROMPT 16 /* Do not prompt before overwriting files */
44 #define HELP 32 /* Help was asked for */
45 #define SOURCE 128 /* File is a source */
48 typedef struct tagFILES
50 struct tagFILES *next;
51 TCHAR szFile[MAX_PATH];
52 DWORD dwFlag; /* BINARY -xor- ASCII */
56 static BOOL DoSwitches (LPTSTR, LPDWORD);
57 static BOOL AddFile (LPFILES, char *, int *, int *, LPDWORD);
58 static BOOL AddFiles (LPFILES, char *, int *, int *, int *, LPDWORD);
59 static BOOL GetDestination (LPFILES, LPFILES);
60 static INT ParseCommand (LPFILES, int, char **, LPDWORD);
61 static VOID DeleteFileList (LPFILES);
62 static INT Overwrite (LPTSTR);
67 IsDirectory (LPTSTR fn)
69 if (!IsValidFileName (fn))
71 return (GetFileAttributes (fn) & FILE_ATTRIBUTE_DIRECTORY);
76 DoSwitches (LPTSTR arg, LPDWORD lpdwFlags)
78 if (!_tcsicmp (arg, _T("/-Y")))
81 *lpdwFlags &= ~NPROMPT;
84 else if (_tcslen (arg) > 2)
86 error_too_many_parameters ("");
90 switch (_totupper (arg[1]))
98 *lpdwFlags &= ~BINARY;
102 *lpdwFlags |= BINARY;
103 *lpdwFlags &= ~ASCII;
107 *lpdwFlags &= ~PROMPT;
108 *lpdwFlags |= NPROMPT;
112 error_invalid_switch (arg[1]);
120 AddFile (LPFILES f, char *arg, int *source, int *dest, LPDWORD flags)
124 error_too_many_parameters ("");
137 _tcscpy(f->szFile, arg);
138 f->dwFlag |= *flags & ASCII ? ASCII : BINARY;
139 if ((f->next = (LPFILES)malloc (sizeof (FILES))) == NULL)
141 error_out_of_memory ();
152 AddFiles (LPFILES f, char *arg, int *source, int *dest,
153 int *count, LPDWORD flags)
161 error_too_many_parameters ("");
168 while (arg[j] == _T('+'))
171 while (arg[j] != _T('\0'))
174 if (t[k] == '+' || arg[j] == _T('\0'))
178 if (arg[j] == _T('\0') && t[k] != _T('+'))
182 _tcscpy (f->szFile, t);
185 f->dwFlag |= *flags | SOURCE | ASCII;
187 f->dwFlag |= *flags | BINARY | SOURCE;
189 if ((f->next = (LPFILES)malloc (sizeof (FILES))) == NULL)
191 error_out_of_memory ();
203 if (arg[--j] == _T('+'))
211 GetDestination (LPFILES f, LPFILES dest)
216 while (f->next != NULL)
224 if ((f->dwFlag & SOURCE) == 0)
228 _tcscpy (dest->szFile, f->szFile);
229 dest->dwFlag = f->dwFlag;
240 ParseCommand (LPFILES f, int argc, char **arg, LPDWORD lpdwFlags)
251 for (i = 0; i < argc; i++)
253 if (arg[i][0] == _T('/'))
255 if (!DoSwitches (arg[i], lpdwFlags))
260 if (!_tcscmp(arg[i], _T("+")))
262 else if (!_tcschr(arg[i], _T('+')) && source)
264 if (!AddFile(f, arg[i], &source, &dest, lpdwFlags))
271 if (!AddFiles(f, arg[i], &source, &dest, &count, lpdwFlags))
273 while (f->next != NULL)
280 DebugPrintf ("ParseCommand: flags has %s\n",
281 *lpdwFlags & ASCII ? "ASCII" : "BINARY");
288 DeleteFileList (LPFILES f)
302 Overwrite (LPTSTR fn)
307 ConOutPrintf (_T("Overwrite %s (Yes/No/All)? "), fn);
308 ConInString (inp, 10);
312 for (p = inp; _istspace (*p); p++)
315 if (*p != _T('Y') && *p != _T('A'))
324 #define BUFF_SIZE 16384 /* 16k = max buffer size */
327 int copy (LPTSTR source, LPTSTR dest, int append, LPDWORD lpdwFlags)
340 DebugPrintf ("checking mode\n");
343 dwAttrib = GetFileAttributes (source);
345 hFileSrc = CreateFile (source, GENERIC_READ, FILE_SHARE_READ,
346 NULL, OPEN_EXISTING, 0, NULL);
347 if (hFileSrc == INVALID_HANDLE_VALUE)
349 ConErrPrintf (_T("Error: Cannot open source - %s!\n"), source);
354 DebugPrintf (_T("getting time\n"));
357 GetFileTime (hFileSrc, &srctime, NULL, NULL);
360 DebugPrintf (_T("copy: flags has %s\n"),
361 *lpdwFlags & ASCII ? "ASCII" : "BINARY");
364 if (!IsValidFileName (dest))
367 DebugPrintf (_T("opening/creating\n"));
370 CreateFile (dest, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
374 if (!_tcscmp (dest, source))
376 ConErrPrintf (_T("Error: Can't copy onto itself!\n"));
377 CloseHandle (hFileSrc);
382 DebugPrintf (_T("SetFileAttributes (%s, FILE_ATTRIBUTE_NORMAL);\n"), dest);
384 SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
387 DebugPrintf (_T("DeleteFile (%s);\n"), dest);
392 CreateFile (dest, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
396 LONG lFilePosHigh = 0;
398 if (!_tcscmp (dest, source))
400 CloseHandle (hFileSrc);
405 DebugPrintf (_T("opening/appending\n"));
408 CreateFile (dest, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
409 SetFilePointer (hFileDest, 0, &lFilePosHigh,FILE_END);
412 if (hFileDest == INVALID_HANDLE_VALUE)
414 CloseHandle (hFileSrc);
415 error_path_not_found ();
419 buffer = (LPBYTE)malloc (BUFF_SIZE);
422 CloseHandle (hFileDest);
423 CloseHandle (hFileSrc);
424 error_out_of_memory ();
430 ReadFile (hFileSrc, buffer, BUFF_SIZE, &dwRead, NULL);
431 if (*lpdwFlags & ASCII)
433 for (i = 0; i < dwRead; i++)
435 if (((LPTSTR)buffer)[i] == 0x1A)
447 WriteFile (hFileDest, buffer, dwRead, &dwWritten, NULL);
448 if (dwWritten != dwRead)
450 ConErrPrintf (_T("Error writing destination!\n"));
452 CloseHandle (hFileDest);
453 CloseHandle (hFileSrc);
457 while (dwRead && !bEof);
460 DebugPrintf (_T("setting time\n"));
462 SetFileTime (hFileDest, &srctime, NULL, NULL);
464 if (*lpdwFlags & ASCII)
466 ((LPTSTR)buffer)[0] = 0x1A;
467 ((LPTSTR)buffer)[1] = _T('\0');
469 DebugPrintf (_T("appending ^Z\n"));
471 WriteFile (hFileDest, buffer, sizeof(TCHAR), &dwWritten, NULL);
475 CloseHandle (hFileDest);
476 CloseHandle (hFileSrc);
479 DebugPrintf (_T("setting mode\n"));
481 SetFileAttributes (dest, dwAttrib);
488 SetupCopy (LPFILES sources, char **p, BOOL bMultiple,
489 char *drive_d, char *dir_d, char *file_d,
490 char *ext_d, int *append, LPDWORD lpdwFlags)
492 WIN32_FIND_DATA find;
494 char drive_s[_MAX_DRIVE];
495 CHAR dir_s[_MAX_DIR];
496 char file_s[_MAX_FNAME];
497 char ext_s[_MAX_EXT];
498 char from_merge[_MAX_PATH];
509 DebugPrintf (_T("SetupCopy\n"));
512 real_source = (LPTSTR)malloc (MAX_PATH);
513 real_dest = (LPTSTR)malloc (MAX_PATH);
515 if (!real_source || !real_dest)
517 error_out_of_memory ();
518 DeleteFileList (sources);
525 while (sources->next != NULL)
527 _splitpath (sources->szFile, drive_s, dir_s, file_s, ext_s);
528 hFind = FindFirstFile (sources->szFile, &find);
529 if (hFind == INVALID_HANDLE_VALUE)
531 error_file_not_found();
540 if (find.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
543 _makepath(from_merge, drive_d, dir_d, file_d, ext_d);
544 if (from_merge[_tcslen(from_merge) - 1] == _T('\\'))
545 from_merge[_tcslen(from_merge) - 1] = 0;
547 if (IsDirectory (from_merge))
550 _tcscat (from_merge, _T("\\"));
551 _tcscat (from_merge, find.cFileName);
556 _tcscpy (real_dest, from_merge);
557 _makepath (real_source, drive_s, dir_s, find.cFileName, NULL);
560 DebugPrintf (_T("copying %s -> %s (%sappending%s)\n"),
561 real_source, real_dest,
562 *append ? "" : "not ",
563 sources->dwFlag & ASCII ? ", ASCII" : ", BINARY");
566 if (IsValidFileName (real_dest) && !bAll)
568 /* Don't prompt in a batch file */
577 over = Overwrite (real_dest);
586 if (copy (real_source, real_dest, *append, lpdwFlags))
589 bDone = FindNextFile (hFind, &find);
597 sources = sources->next;
607 INT cmd_copy (LPTSTR first, LPTSTR rest)
610 char drive_d[_MAX_DRIVE];
611 char dir_d[_MAX_DIR];
612 char file_d[_MAX_FNAME];
613 char ext_d[_MAX_EXT];
620 LPFILES sources = NULL;
621 LPFILES start = NULL;
628 if (!_tcsncmp (rest, _T("/?"), 2))
630 ConOutPuts (_T("Copies one or more files to another location.\n"
632 "COPY [/V][/Y|/-Y][/A|/B] source [/A|/B]\n"
633 " [+ source [/A|/B] [+ ...]] [destination [/A|/B]]\n"
635 " source Specifies the file or files to be copied.\n"
636 " /A Indicates an ASCII text file.\n"
637 " /B Indicates a binary file.\n"
638 " destination Specifies the directory and/or filename for the new file(s).\n"
639 " /V Verifies that new files are written correctly.\n"
640 " /Y Suppresses prompting to confirm you want to overwrite an\n"
641 " existing destination file.\n"
642 " /-Y Causes prompting to confirm you want to overwrite an\n"
643 " existing destination file.\n"
645 "The switch /Y may be present in the COPYCMD environment variable.\n"
650 p = split (rest, &argc, FALSE);
654 error_req_param_missing ();
658 sources = (LPFILES)malloc (sizeof (FILES));
661 error_out_of_memory ();
664 sources->next = NULL;
667 if ((files = ParseCommand (sources, argc, p, &dwFlags)) == -1)
669 DeleteFileList (sources);
675 error_req_param_missing();
676 DeleteFileList (sources);
682 bDestFound = GetDestination (sources, &dest);
685 _splitpath (dest.szFile, drive_d, dir_d, file_d, ext_d);
686 if (IsDirectory (dest.szFile))
688 _tcscat (dir_d, file_d);
689 _tcscat (dir_d, ext_d);
690 file_d[0] = _T('\0');
695 if (_tcschr (dest.szFile, _T('*')) || _tcschr (dest.szFile, _T('?')))
700 if (strchr(rest, '+'))
708 if (bDestFound && !bWildcards)
710 copied = SetupCopy (sources, p, bMultiple, drive_d, dir_d, file_d, ext_d, &append, &dwFlags);
712 else if (bDestFound && bWildcards)
714 ConErrPrintf (_T("Error: Not implemented yet!\n"));
715 DeleteFileList (sources);
719 else if (!bDestFound && !bMultiple)
721 _splitpath (sources->szFile, drive_d, dir_d, file_d, ext_d);
722 if (IsDirectory (sources->szFile))
724 _tcscat (dir_d, file_d);
725 _tcscat (dir_d, ext_d);
726 file_d[0] = _T('\0');
729 copied = SetupCopy (sources, p, FALSE, "", "", file_d, ext_d, &append, &dwFlags);
733 _splitpath(sources->szFile, drive_d, dir_d, file_d, ext_d);
734 if (IsDirectory (sources->szFile))
736 _tcscat (dir_d, file_d);
737 _tcscat (dir_d, ext_d);
738 file_d[0] = _T('\0');
742 ConOutPuts (sources->szFile);
744 copied = SetupCopy (sources->next, p, bMultiple, drive_d, dir_d, file_d, ext_d, &append, &dwFlags) + 1;
747 DeleteFileList (sources);
749 ConOutPrintf (_T(" %d file(s) copied\n"), copied);
753 #endif /* INCLUDE_CMD_COPY */