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.
20 * 27-Oct-1998 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
21 * Disabled prompting when used in batch mode.
23 * 03-Apr-2005 (Magnus Olsen) <magnus@greatlord.com>)
24 * Remove all hardcode string to En.rc
30 #ifdef INCLUDE_CMD_COPY
33 #define VERIFY 1 /* VERIFY Switch */
34 #define BINARY 2 /* File is to be copied as BINARY */
35 #define ASCII 4 /* File is to be copied as ASCII */
36 #define PROMPT 8 /* Prompt before overwriting files */
37 #define NPROMPT 16 /* Do not prompt before overwriting files */
38 #define HELP 32 /* Help was asked for */
39 #define SOURCE 128 /* File is a source */
42 typedef struct tagFILES
44 struct tagFILES
*next
;
45 TCHAR szFile
[MAX_PATH
];
46 DWORD dwFlag
; /* BINARY -xor- ASCII */
50 static BOOL
DoSwitches (LPTSTR
, LPDWORD
);
51 static BOOL
AddFile (LPFILES
, TCHAR
*, int *, int *, LPDWORD
);
52 static BOOL
AddFiles (LPFILES
, TCHAR
*, int *, int *, int *, LPDWORD
);
53 static BOOL
GetDestination (LPFILES
, LPFILES
);
54 static INT
ParseCommand (LPFILES
, int, TCHAR
**, LPDWORD
);
55 static VOID
DeleteFileList (LPFILES
);
56 static INT
Overwrite (LPTSTR
);
60 DoSwitches (LPTSTR arg
, LPDWORD lpdwFlags
)
62 if (!_tcsicmp (arg
, _T("/-Y")))
65 *lpdwFlags
&= ~NPROMPT
;
68 else if (_tcslen (arg
) > 2)
70 error_too_many_parameters (_T(""));
74 switch (_totupper (arg
[1]))
82 *lpdwFlags
&= ~BINARY
;
91 *lpdwFlags
&= ~PROMPT
;
92 *lpdwFlags
|= NPROMPT
;
96 error_invalid_switch (arg
[1]);
104 AddFile (LPFILES f
, TCHAR
*arg
, int *source
, int *dest
, LPDWORD flags
)
108 error_too_many_parameters (_T(""));
121 _tcscpy(f
->szFile
, arg
);
122 f
->dwFlag
|= *flags
& ASCII
? ASCII
: BINARY
;
123 if ((f
->next
= (LPFILES
)malloc (sizeof (FILES
))) == NULL
)
125 error_out_of_memory ();
136 AddFiles (LPFILES f
, TCHAR
*arg
, int *source
, int *dest
,
137 int *count
, LPDWORD flags
)
145 error_too_many_parameters (_T(""));
152 while (arg
[j
] == _T('+'))
155 while (arg
[j
] != _T('\0'))
158 if (t
[k
] == '+' || arg
[j
] == _T('\0'))
162 if (arg
[j
] == _T('\0') && t
[k
] != _T('+'))
166 _tcscpy (f
->szFile
, t
);
169 f
->dwFlag
|= *flags
| SOURCE
| ASCII
;
171 f
->dwFlag
|= *flags
| BINARY
| SOURCE
;
173 if ((f
->next
= (LPFILES
)malloc (sizeof (FILES
))) == NULL
)
175 error_out_of_memory ();
187 if (arg
[--j
] == _T('+'))
195 GetDestination (LPFILES f
, LPFILES dest
)
200 while (f
->next
!= NULL
)
208 if ((f
->dwFlag
& SOURCE
) == 0)
212 _tcscpy (dest
->szFile
, f
->szFile
);
213 dest
->dwFlag
= f
->dwFlag
;
224 ParseCommand (LPFILES f
, int argc
, TCHAR
**arg
, LPDWORD lpdwFlags
)
235 for (i
= 0; i
< argc
; i
++)
237 if (arg
[i
][0] == _T('/'))
239 if (!DoSwitches (arg
[i
], lpdwFlags
))
244 if (!_tcscmp(arg
[i
], _T("+")))
246 else if (!_tcschr(arg
[i
], _T('+')) && source
)
249 // Make sure we have a clean workable path
251 GetFullPathName( arg
[i
], 128, (LPTSTR
) &temp
, NULL
);
252 // printf("A Input %s, Output %s\n", arg[i], temp);
254 if (!AddFile(f
, (TCHAR
*) &temp
, &source
, &dest
, lpdwFlags
))
262 GetFullPathName( arg
[i
], 128, (LPTSTR
) &temp
, NULL
);
263 // printf("B Input %s, Output %s\n", arg[i], temp);
265 if (!AddFiles(f
, (TCHAR
*) &temp
, &source
, &dest
, &count
, lpdwFlags
))
267 while (f
->next
!= NULL
)
274 DebugPrintf (_T("ParseCommand: flags has %s\n"),
275 *lpdwFlags
& ASCII
? _T("ASCII") : _T("BINARY"));
282 DeleteFileList (LPFILES f
)
296 Overwrite (LPTSTR fn
)
298 TCHAR szMsg
[RC_STRING_MAX_SIZE
];
303 LoadString( GetModuleHandle(NULL
), STRING_COPY_OPTION
, szOptions
, 4);
305 LoadString(GetModuleHandle(NULL
), STRING_COPY_HELP1
, szMsg
, RC_STRING_MAX_SIZE
);
308 ConInString(inp
, 10);
312 for (p
= inp
; _istspace (*p
); p
++)
315 if (*p
!= szOptions
[0] && *p
!= szOptions
[2])
317 if (*p
== szOptions
[2])
324 #define BUFF_SIZE 16384 /* 16k = max buffer size */
327 int copy (LPTSTR source
, LPTSTR dest
, int append
, LPDWORD lpdwFlags
)
329 TCHAR szMsg
[RC_STRING_MAX_SIZE
];
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 LoadString(GetModuleHandle(NULL
), STRING_COPY_ERROR1
, szMsg
, RC_STRING_MAX_SIZE
);
351 ConErrPrintf(szMsg
, source
);
356 DebugPrintf (_T("getting time\n"));
359 GetFileTime (hFileSrc
, &srctime
, NULL
, NULL
);
362 DebugPrintf (_T("copy: flags has %s\n"),
363 *lpdwFlags
& ASCII
? "ASCII" : "BINARY");
366 if (!IsExistingFile (dest
))
369 DebugPrintf (_T("opening/creating\n"));
372 CreateFile (dest
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, NULL
);
376 if (!_tcscmp (dest
, source
))
378 LoadString(GetModuleHandle(NULL
), STRING_COPY_ERROR2
, szMsg
, RC_STRING_MAX_SIZE
);
379 ConErrPrintf(szMsg
, source
);
381 CloseHandle (hFileSrc
);
386 DebugPrintf (_T("SetFileAttributes (%s, FILE_ATTRIBUTE_NORMAL);\n"), dest
);
388 SetFileAttributes (dest
, FILE_ATTRIBUTE_NORMAL
);
391 DebugPrintf (_T("DeleteFile (%s);\n"), dest
);
396 CreateFile (dest
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, NULL
);
400 LONG lFilePosHigh
= 0;
402 if (!_tcscmp (dest
, source
))
404 CloseHandle (hFileSrc
);
409 DebugPrintf (_T("opening/appending\n"));
412 CreateFile (dest
, GENERIC_WRITE
, 0, NULL
, OPEN_EXISTING
, 0, NULL
);
413 SetFilePointer (hFileDest
, 0, &lFilePosHigh
,FILE_END
);
416 if (hFileDest
== INVALID_HANDLE_VALUE
)
418 CloseHandle (hFileSrc
);
419 error_path_not_found ();
423 buffer
= (LPBYTE
)malloc (BUFF_SIZE
);
426 CloseHandle (hFileDest
);
427 CloseHandle (hFileSrc
);
428 error_out_of_memory ();
434 ReadFile (hFileSrc
, buffer
, BUFF_SIZE
, &dwRead
, NULL
);
435 if (*lpdwFlags
& ASCII
)
437 for (i
= 0; i
< dwRead
; i
++)
439 if (((LPTSTR
)buffer
)[i
] == 0x1A)
451 WriteFile (hFileDest
, buffer
, dwRead
, &dwWritten
, NULL
);
452 if (dwWritten
!= dwRead
)
455 LoadString(GetModuleHandle(NULL
), STRING_COPY_ERROR3
, szMsg
, RC_STRING_MAX_SIZE
);
459 CloseHandle (hFileDest
);
460 CloseHandle (hFileSrc
);
464 while (dwRead
&& !bEof
);
467 DebugPrintf (_T("setting time\n"));
469 SetFileTime (hFileDest
, &srctime
, NULL
, NULL
);
471 if (*lpdwFlags
& ASCII
)
473 ((LPTSTR
)buffer
)[0] = 0x1A;
474 ((LPTSTR
)buffer
)[1] = _T('\0');
476 DebugPrintf (_T("appending ^Z\n"));
478 WriteFile (hFileDest
, buffer
, sizeof(TCHAR
), &dwWritten
, NULL
);
482 CloseHandle (hFileDest
);
483 CloseHandle (hFileSrc
);
486 DebugPrintf (_T("setting mode\n"));
488 SetFileAttributes (dest
, dwAttrib
);
495 SetupCopy (LPFILES sources
, TCHAR
**p
, BOOL bMultiple
,
496 TCHAR
*drive_d
, TCHAR
*dir_d
, TCHAR
*file_d
,
497 TCHAR
*ext_d
, int *append
, LPDWORD lpdwFlags
)
499 WIN32_FIND_DATA find
;
500 TCHAR drive_s
[_MAX_DRIVE
];
501 TCHAR dir_s
[_MAX_DIR
];
502 TCHAR file_s
[_MAX_FNAME
];
503 TCHAR ext_s
[_MAX_EXT
];
504 TCHAR from_merge
[_MAX_PATH
];
516 DebugPrintf (_T("SetupCopy\n"));
519 real_source
= (LPTSTR
)malloc (MAX_PATH
* sizeof(TCHAR
));
520 real_dest
= (LPTSTR
)malloc (MAX_PATH
* sizeof(TCHAR
));
522 if (!real_source
|| !real_dest
)
524 error_out_of_memory ();
525 DeleteFileList (sources
);
532 while (sources
->next
!= NULL
)
535 /* Force a clean full path
537 GetFullPathName( sources
->szFile
, 128, (LPTSTR
) &temp
, NULL
);
538 if (IsExistingDirectory(temp
))
540 _tcscat(temp
, _T("\\*"));
543 _tsplitpath (temp
, drive_s
, dir_s
, file_s
, ext_s
);
545 hFind
= FindFirstFile ((TCHAR
*)&temp
, &find
);
546 if (hFind
== INVALID_HANDLE_VALUE
)
548 error_file_not_found();
557 if (find
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
560 _tmakepath(from_merge
, drive_d
, dir_d
, file_d
, ext_d
);
562 if (from_merge
[_tcslen(from_merge
) - 1] == _T('\\'))
563 from_merge
[_tcslen(from_merge
) - 1] = 0;
565 // printf("Merge %s, filename %s\n", from_merge, find.cFileName);
567 if (IsExistingDirectory (from_merge
))
570 // printf("Merge DIR\n");
573 _tcscat (from_merge
, _T("\\"));
574 _tcscat (from_merge
, find
.cFileName
);
579 _tcscpy (real_dest
, from_merge
);
580 _tmakepath (real_source
, drive_s
, dir_s
, find
.cFileName
, NULL
);
583 DebugPrintf(_T("copying %S -> %S (%Sappending%S)\n"),
584 real_source
, real_dest
,
585 *append
? _T("") : _T("not "),
586 sources
->dwFlag
& ASCII
? _T(", ASCII") : _T(", BINARY"));
589 if (IsExistingFile (real_dest
) && !bAll
)
591 /* Don't prompt in a batch file */
600 over
= Overwrite (real_dest
);
609 if (copy (real_source
, real_dest
, *append
, lpdwFlags
))
612 bDone
= FindNextFile (hFind
, &find
);
620 sources
= sources
->next
;
630 INT
cmd_copy (LPTSTR first
, LPTSTR rest
)
632 TCHAR szMsg
[RC_STRING_MAX_SIZE
];
634 TCHAR drive_d
[_MAX_DRIVE
];
635 TCHAR dir_d
[_MAX_DIR
];
636 TCHAR file_d
[_MAX_FNAME
];
637 TCHAR ext_d
[_MAX_EXT
];
644 LPFILES sources
= NULL
;
645 LPFILES start
= NULL
;
652 if (!_tcsncmp (rest
, _T("/?"), 2))
654 LoadString(GetModuleHandle(NULL
), STRING_COPY_HELP2
, szMsg
, RC_STRING_MAX_SIZE
);
659 p
= split (rest
, &argc
, FALSE
);
663 error_req_param_missing ();
667 sources
= (LPFILES
)malloc (sizeof (FILES
));
670 error_out_of_memory ();
673 sources
->next
= NULL
;
676 if ((files
= ParseCommand (sources
, argc
, p
, &dwFlags
)) == -1)
678 DeleteFileList (sources
);
684 error_req_param_missing();
685 DeleteFileList (sources
);
691 bDestFound
= GetDestination (sources
, &dest
);
694 _tsplitpath (dest
.szFile
, drive_d
, dir_d
, file_d
, ext_d
);
695 if (IsExistingDirectory (dest
.szFile
))
697 // printf("A szFile= %s, Dir = %s, File = %s, Ext = %s\n", dest.szFile, dir_d, file_d, ext_d);
698 _tcscat (dir_d
, file_d
);
699 _tcscat (dir_d
, ext_d
);
700 file_d
[0] = _T('\0');
705 if (_tcschr (dest
.szFile
, _T('*')) || _tcschr (dest
.szFile
, _T('?')))
710 if (_tcschr(rest
, _T('+')))
718 if (bDestFound
&& !bWildcards
)
721 // _tcscpy(sources->szFile, dest.szFile);
723 copied
= SetupCopy (sources
, p
, bMultiple
, drive_d
, dir_d
, file_d
, ext_d
, &append
, &dwFlags
);
725 else if (bDestFound
&& bWildcards
)
727 LoadString(GetModuleHandle(NULL
), STRING_COPY_ERROR4
, szMsg
, RC_STRING_MAX_SIZE
);
730 DeleteFileList (sources
);
734 else if (!bDestFound
&& !bMultiple
)
736 _tsplitpath (sources
->szFile
, drive_d
, dir_d
, file_d
, ext_d
);
737 if (IsExistingDirectory (sources
->szFile
))
739 // printf("B File = %s, Ext = %s\n", file_d, ext_d);
741 _tcscat (dir_d
, file_d
);
742 _tcscat (dir_d
, ext_d
);
743 file_d
[0] = _T('\0');
746 copied
= SetupCopy (sources
, p
, FALSE
, _T(""), _T(""), file_d
, ext_d
, &append
, &dwFlags
);
750 _tsplitpath(sources
->szFile
, drive_d
, dir_d
, file_d
, ext_d
);
751 if (IsExistingDirectory (sources
->szFile
))
753 // printf("C File = %s, Ext = %s\n", file_d, ext_d);
755 _tcscat (dir_d
, file_d
);
756 _tcscat (dir_d
, ext_d
);
757 file_d
[0] = _T('\0');
761 ConOutPuts (sources
->szFile
);
763 copied
= SetupCopy (sources
->next
, p
, bMultiple
, drive_d
, dir_d
, file_d
, ext_d
, &append
, &dwFlags
) + 1;
766 DeleteFileList (sources
);
768 ConOutPrintf (_T(" %d file(s) copied\n"), copied
);
772 #endif /* INCLUDE_CMD_COPY */