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
)
302 LoadString( CMD_ModuleHandle
, STRING_COPY_OPTION
, szOptions
, sizeof(szOptions
) / sizeof(szOptions
[0]) );
304 ConOutResPuts(STRING_COPY_HELP1
);
306 ConInString(inp
, 10);
310 for (p
= inp
; _istspace (*p
); p
++)
313 if (*p
!= szOptions
[0] && *p
!= szOptions
[2])
315 if (*p
== szOptions
[2])
322 #define BUFF_SIZE 16384 /* 16k = max buffer size */
325 int copy (LPTSTR source
, LPTSTR dest
, int append
, LPDWORD lpdwFlags
)
327 TCHAR szMsg
[RC_STRING_MAX_SIZE
];
339 DebugPrintf (_T("checking mode\n"));
342 dwAttrib
= GetFileAttributes (source
);
344 hFileSrc
= CreateFile (source
, GENERIC_READ
, FILE_SHARE_READ
,
345 NULL
, OPEN_EXISTING
, 0, NULL
);
346 if (hFileSrc
== INVALID_HANDLE_VALUE
)
348 LoadString(CMD_ModuleHandle
, STRING_COPY_ERROR1
, szMsg
, RC_STRING_MAX_SIZE
);
349 ConErrPrintf(szMsg
, 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 (!IsExistingFile (dest
))
367 DebugPrintf (_T("opening/creating\n"));
370 CreateFile (dest
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, NULL
);
374 if (!_tcscmp (dest
, source
))
376 LoadString(CMD_ModuleHandle
, STRING_COPY_ERROR2
, szMsg
, RC_STRING_MAX_SIZE
);
377 ConErrPrintf(szMsg
, source
);
379 CloseHandle (hFileSrc
);
384 DebugPrintf (_T("SetFileAttributes (%s, FILE_ATTRIBUTE_NORMAL);\n"), dest
);
386 SetFileAttributes (dest
, FILE_ATTRIBUTE_NORMAL
);
389 DebugPrintf (_T("DeleteFile (%s);\n"), dest
);
394 CreateFile (dest
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, NULL
);
398 LONG lFilePosHigh
= 0;
400 if (!_tcscmp (dest
, source
))
402 CloseHandle (hFileSrc
);
407 DebugPrintf (_T("opening/appending\n"));
410 CreateFile (dest
, GENERIC_WRITE
, 0, NULL
, OPEN_EXISTING
, 0, NULL
);
411 SetFilePointer (hFileDest
, 0, &lFilePosHigh
,FILE_END
);
414 if (hFileDest
== INVALID_HANDLE_VALUE
)
416 CloseHandle (hFileSrc
);
417 error_path_not_found ();
421 buffer
= (LPBYTE
)malloc (BUFF_SIZE
);
424 CloseHandle (hFileDest
);
425 CloseHandle (hFileSrc
);
426 error_out_of_memory ();
432 ReadFile (hFileSrc
, buffer
, BUFF_SIZE
, &dwRead
, NULL
);
433 if (*lpdwFlags
& ASCII
)
435 for (i
= 0; i
< dwRead
; i
++)
437 if (((LPTSTR
)buffer
)[i
] == 0x1A)
449 WriteFile (hFileDest
, buffer
, dwRead
, &dwWritten
, NULL
);
450 if (dwWritten
!= dwRead
)
452 ConErrResPuts(STRING_COPY_ERROR3
);
455 CloseHandle (hFileDest
);
456 CloseHandle (hFileSrc
);
460 while (dwRead
&& !bEof
);
463 DebugPrintf (_T("setting time\n"));
465 SetFileTime (hFileDest
, &srctime
, NULL
, NULL
);
467 if (*lpdwFlags
& ASCII
)
469 ((LPTSTR
)buffer
)[0] = 0x1A;
470 ((LPTSTR
)buffer
)[1] = _T('\0');
472 DebugPrintf (_T("appending ^Z\n"));
474 WriteFile (hFileDest
, buffer
, sizeof(TCHAR
), &dwWritten
, NULL
);
478 CloseHandle (hFileDest
);
479 CloseHandle (hFileSrc
);
482 DebugPrintf (_T("setting mode\n"));
484 SetFileAttributes (dest
, dwAttrib
);
491 SetupCopy (LPFILES sources
, TCHAR
**p
, BOOL bMultiple
,
492 TCHAR
*drive_d
, TCHAR
*dir_d
, TCHAR
*file_d
,
493 TCHAR
*ext_d
, int *append
, LPDWORD lpdwFlags
)
495 WIN32_FIND_DATA find
;
496 TCHAR drive_s
[_MAX_DRIVE
];
497 TCHAR dir_s
[_MAX_DIR
];
498 TCHAR file_s
[_MAX_FNAME
];
499 TCHAR ext_s
[_MAX_EXT
];
500 TCHAR from_merge
[_MAX_PATH
];
512 DebugPrintf (_T("SetupCopy\n"));
515 real_source
= (LPTSTR
)malloc (MAX_PATH
* sizeof(TCHAR
));
516 real_dest
= (LPTSTR
)malloc (MAX_PATH
* sizeof(TCHAR
));
518 if (!real_source
|| !real_dest
)
520 error_out_of_memory ();
521 DeleteFileList (sources
);
528 while (sources
->next
!= NULL
)
531 /* Force a clean full path
533 GetFullPathName( sources
->szFile
, 128, (LPTSTR
) &temp
, NULL
);
534 if (IsExistingDirectory(temp
))
536 _tcscat(temp
, _T("\\*"));
539 _tsplitpath (temp
, drive_s
, dir_s
, file_s
, ext_s
);
541 hFind
= FindFirstFile ((TCHAR
*)&temp
, &find
);
542 if (hFind
== INVALID_HANDLE_VALUE
)
544 error_file_not_found();
553 if (find
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
556 _tmakepath(from_merge
, drive_d
, dir_d
, file_d
, ext_d
);
558 if (from_merge
[_tcslen(from_merge
) - 1] == _T('\\'))
559 from_merge
[_tcslen(from_merge
) - 1] = 0;
561 // printf("Merge %s, filename %s\n", from_merge, find.cFileName);
563 if (IsExistingDirectory (from_merge
))
566 // printf("Merge DIR\n");
569 _tcscat (from_merge
, _T("\\"));
570 _tcscat (from_merge
, find
.cFileName
);
575 _tcscpy (real_dest
, from_merge
);
576 _tmakepath (real_source
, drive_s
, dir_s
, find
.cFileName
, NULL
);
579 DebugPrintf(_T("copying %S -> %S (%Sappending%S)\n"),
580 real_source
, real_dest
,
581 *append
? _T("") : _T("not "),
582 sources
->dwFlag
& ASCII
? _T(", ASCII") : _T(", BINARY"));
585 if (IsExistingFile (real_dest
) && !bAll
)
587 /* Don't prompt in a batch file */
596 over
= Overwrite (real_dest
);
605 if (copy (real_source
, real_dest
, *append
, lpdwFlags
))
608 bDone
= FindNextFile (hFind
, &find
);
616 sources
= sources
->next
;
626 INT
cmd_copy (LPTSTR first
, LPTSTR rest
)
629 TCHAR drive_d
[_MAX_DRIVE
];
630 TCHAR dir_d
[_MAX_DIR
];
631 TCHAR file_d
[_MAX_FNAME
];
632 TCHAR ext_d
[_MAX_EXT
];
633 TCHAR szMsg
[RC_STRING_MAX_SIZE
];
640 LPFILES sources
= NULL
;
641 LPFILES start
= NULL
;
648 if (!_tcsncmp (rest
, _T("/?"), 2))
650 ConOutResPaging(TRUE
,STRING_COPY_HELP2
);
654 p
= split (rest
, &argc
, FALSE
);
658 error_req_param_missing ();
662 sources
= (LPFILES
)malloc (sizeof (FILES
));
665 error_out_of_memory ();
668 sources
->next
= NULL
;
671 if ((files
= ParseCommand (sources
, argc
, p
, &dwFlags
)) == -1)
673 DeleteFileList (sources
);
679 error_req_param_missing();
680 DeleteFileList (sources
);
686 bDestFound
= GetDestination (sources
, &dest
);
689 _tsplitpath (dest
.szFile
, drive_d
, dir_d
, file_d
, ext_d
);
690 if (IsExistingDirectory (dest
.szFile
))
692 // printf("A szFile= %s, Dir = %s, File = %s, Ext = %s\n", dest.szFile, dir_d, file_d, ext_d);
693 _tcscat (dir_d
, file_d
);
694 _tcscat (dir_d
, ext_d
);
695 file_d
[0] = _T('\0');
700 if (_tcschr (dest
.szFile
, _T('*')) || _tcschr (dest
.szFile
, _T('?')))
705 if (_tcschr(rest
, _T('+')))
713 if (bDestFound
&& !bWildcards
)
716 // _tcscpy(sources->szFile, dest.szFile);
718 copied
= SetupCopy (sources
, p
, bMultiple
, drive_d
, dir_d
, file_d
, ext_d
, &append
, &dwFlags
);
720 else if (bDestFound
&& bWildcards
)
722 ConErrResPuts(STRING_COPY_ERROR4
);
724 DeleteFileList (sources
);
728 else if (!bDestFound
&& !bMultiple
)
730 _tsplitpath (sources
->szFile
, drive_d
, dir_d
, file_d
, ext_d
);
731 if (IsExistingDirectory (sources
->szFile
))
733 // printf("B File = %s, Ext = %s\n", file_d, ext_d);
735 _tcscat (dir_d
, file_d
);
736 _tcscat (dir_d
, ext_d
);
737 file_d
[0] = _T('\0');
740 copied
= SetupCopy (sources
, p
, FALSE
, _T(""), _T(""), file_d
, ext_d
, &append
, &dwFlags
);
744 _tsplitpath(sources
->szFile
, drive_d
, dir_d
, file_d
, ext_d
);
745 if (IsExistingDirectory (sources
->szFile
))
747 // printf("C File = %s, Ext = %s\n", file_d, ext_d);
749 _tcscat (dir_d
, file_d
);
750 _tcscat (dir_d
, ext_d
);
751 file_d
[0] = _T('\0');
755 ConOutPuts (sources
->szFile
);
757 copied
= SetupCopy (sources
->next
, p
, bMultiple
, drive_d
, dir_d
, file_d
, ext_d
, &append
, &dwFlags
) + 1;
760 DeleteFileList (sources
);
763 LoadString( CMD_ModuleHandle
, STRING_COPY_FILE
, szMsg
, RC_STRING_MAX_SIZE
);
764 ConOutPrintf (szMsg
, copied
);
768 #endif /* INCLUDE_CMD_COPY */