mirror of
https://github.com/joncampbell123/dosbox-x.git
synced 2025-05-08 19:32:39 +08:00
Merge pull request #5637 from maron2000/update_xcopy
Update XCOPY to ver 1.9a
This commit is contained in:
commit
bf023ea707
@ -1,4 +1,4 @@
|
||||
# Makefile for XCOPY (using Borland C or Turbo C)
|
||||
# Makefile for XCOPY (using Open Watcom or Borland/Turbo C)
|
||||
# Based on the CHOICE makefile by Tom Ehlert
|
||||
|
||||
# compression (for final executable)
|
||||
@ -7,8 +7,8 @@
|
||||
# if you dont want to UPX choice
|
||||
# if you use upx: --8086 for 8086 compatibility, --best for smallest
|
||||
|
||||
UPX=-rem
|
||||
#UPX=upx -9
|
||||
# UPX=-rem
|
||||
UPX=upx --8086 --best
|
||||
|
||||
|
||||
# set where build files (including intermediate ones) placed
|
||||
@ -29,25 +29,32 @@ RM=del
|
||||
# -ms memory model (s=SMALL), -zq quiet mode
|
||||
# -fe=xxx executable name (must be last)
|
||||
# -o a=relax alias checking s=for size, -zp# 1=byte align
|
||||
#CC=wcl
|
||||
#CFLAGS=-oas -bt=DOS -zp1 -s -ms -0 -wx -we -zq -fm -fe=$*
|
||||
# -k# set stack size, default is 2048 bytes (2KB) but just under 4KB is needed
|
||||
# Note: we default to Watcom unless Borland MAKE is used
|
||||
CC=wcl
|
||||
CFLAGS=-oas -bt=DOS -zp1 -ms -0 -wx -we -zq -fm -k12288 -fe=$*
|
||||
# needed for wmake if phony target
|
||||
#PHONY=.SYMBOLIC
|
||||
PHONY=.SYMBOLIC
|
||||
|
||||
############# TURBO_C ########################
|
||||
# -w warn -M create map -f- no floating point -Z register optimize
|
||||
# -O jump optimize -k- no standard stack frame -K unsigned char
|
||||
# -O jump optimize -k- no standard stack frome -K unsigned char
|
||||
# -exxx executable name (name must be part of option in CFLAGS)
|
||||
# -mt tiny (default is small -ms)
|
||||
# -N stack checking -a- byte alignment -ln no default libs
|
||||
# -lt create .com file -lx no map file ...
|
||||
# -v- quiet mode
|
||||
# -nPATH to place resulting files
|
||||
#CC=bcc
|
||||
CC=tcc
|
||||
# default stack size is 4KB
|
||||
!ifdef __MAKE__ # defined for Borland MAKE but not Watcom WMAKE
|
||||
!ifndef BORLAND
|
||||
CC=bcc # default to BCC, use -DBORLAND=TCC for Turbo C/C++
|
||||
!else
|
||||
CC=$(BORLAND) # Note: make won't use CC as cmd line define
|
||||
!endif
|
||||
CFLAGS=-d -v- -w -M -f- -Z -a- -O -k- -K -ln -ms -e$*
|
||||
PHONY=
|
||||
|
||||
!endif
|
||||
|
||||
CFILES=xcopy.c kitten.c prf.c
|
||||
|
||||
@ -62,7 +69,7 @@ all: xcopy.exe
|
||||
xcopy.exe: $(CFILES) makefile shared.inc kitten.h
|
||||
-$(MKDIR) $(OUTDIR)
|
||||
$(CC) $(CFLAGS) $(CFILES)
|
||||
$(UPX) xcopy.exe
|
||||
-$(UPX) xcopy.exe
|
||||
$(MV) xcopy.exe $(OUTDIR)
|
||||
|
||||
|
||||
|
@ -2,21 +2,6 @@
|
||||
#include <string.h>
|
||||
#include <io.h>
|
||||
|
||||
struct DiskInfo {
|
||||
/* buffer to be filled by INT 21h function 0x7303h */
|
||||
unsigned short size;
|
||||
unsigned short version;
|
||||
unsigned long sectorsPerCluster;
|
||||
unsigned long bytesPerSector;
|
||||
unsigned long availableClusters;
|
||||
unsigned long totalClusters;
|
||||
unsigned long physicalSectorsAvailable;
|
||||
unsigned long totalPhysicalSectors;
|
||||
unsigned long availableAllocationUnits;
|
||||
unsigned long totalAllocationUnits;
|
||||
char reserved[8];
|
||||
};
|
||||
|
||||
#ifdef __WATCOMC__
|
||||
#include <direct.h> /* below: Turbo C dir.h values as comments */
|
||||
#define MAXPATH _MAX_PATH /* 80 */
|
||||
@ -34,6 +19,10 @@ struct DiskInfo {
|
||||
#define FA_DIREC _A_SUBDIR
|
||||
#define FA_ARCH _A_ARCH
|
||||
|
||||
/* following are defined in fcntl.h (here to avoid other conflicts) */
|
||||
#define O_RDONLY 0
|
||||
#define O_RDWR 2
|
||||
|
||||
struct ffblk {
|
||||
unsigned short cr_time; /* time of file creation */
|
||||
unsigned short cr_date; /* date of file creation */
|
||||
@ -91,7 +80,8 @@ int getftime(int handle, struct ftime *ftimep)
|
||||
{
|
||||
union borftime ftm;
|
||||
|
||||
if( _dos_getftime(handle,
|
||||
/* Note: fileno() returns POSIX compatible handle, this may or may not match DOS handle, so convert with os_handle() */
|
||||
if( _dos_getftime(_os_handle(handle),
|
||||
(unsigned *)&ftm.msc_time.date,
|
||||
(unsigned *)&ftm.msc_time.time
|
||||
) == 0 )
|
||||
@ -105,12 +95,42 @@ int setftime(int handle, struct ftime *ftimep)
|
||||
{
|
||||
union borftime ftm;
|
||||
ftm.bc_time = *ftimep;
|
||||
return((_dos_setftime(handle,ftm.msc_time.date,ftm.msc_time.time) == 0) ? 0 : -1);
|
||||
/* Note: fileno() returns POSIX compatible handle, this may or may not match DOS handle, so convert with os_handle() */
|
||||
return((_dos_setftime(_os_handle(handle),ftm.msc_time.date,ftm.msc_time.time) == 0) ? 0 : -1);
|
||||
}
|
||||
|
||||
int os_setftime(const char *src_filename, const char *dest_filename)
|
||||
{
|
||||
int handle;
|
||||
unsigned date, time;
|
||||
int ret;
|
||||
if ((ret = _dos_open(src_filename, O_RDONLY, &handle)) != 0) return ret;
|
||||
if ((ret = _dos_getftime(handle, &date, &time)) != 0) return ret;
|
||||
_dos_close(handle);
|
||||
if ((ret = _dos_open(dest_filename, O_RDWR, &handle)) != 0) return ret;
|
||||
if ((ret = _dos_setftime(handle, date, time)) != 0) return ret;
|
||||
_dos_close(handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
#include <dir.h>
|
||||
|
||||
/* copy file timestamp */
|
||||
int os_setftime(const char *src_filename, const char *dest_filename)
|
||||
{
|
||||
FILE *f;
|
||||
struct ftime filetime;
|
||||
if ((f = fopen(src_filename, "r")) == NULL) return 1;
|
||||
if (getftime(fileno(f), &filetime) != 0) return 1;
|
||||
fclose(f);
|
||||
if ((f = fopen(dest_filename, "w")) == NULL) return 1;
|
||||
if (setftime(fileno(f), &filetime) != 0) return 1;
|
||||
fclose(f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __WATCOMC__ /* "dosdate_t" instead of Borland style "date" ... */
|
||||
@ -123,6 +143,7 @@ int setftime(int handle, struct ftime *ftimep)
|
||||
#define ti_minute minute
|
||||
#define ti_sec second
|
||||
#define ti_hund hsecond
|
||||
#define THETIME struct dostime_t
|
||||
|
||||
time_t dostounix(THEDATE *date, struct dostime_t *time)
|
||||
{
|
||||
@ -140,6 +161,7 @@ time_t dostounix(THEDATE *date, struct dostime_t *time)
|
||||
}
|
||||
#else
|
||||
#define THEDATE struct date
|
||||
#define THETIME struct time
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
@ -233,6 +255,82 @@ void getdfree(unsigned char drive, struct dfree *dtable)
|
||||
}
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/* Gets the free cluster count and clustersize in bytes of disk */
|
||||
/* drive 1=A,2=B,3=C,... error can be NULL if don't care */
|
||||
/*-------------------------------------------------------------------------*/
|
||||
void getdiskfreeclusters(unsigned drive, unsigned long *clustersize, unsigned long *free_clusters)
|
||||
{
|
||||
static char rootname[] = "C:\\";
|
||||
static union REGS r;
|
||||
static struct SREGS s;
|
||||
static struct {
|
||||
unsigned short whatever;
|
||||
unsigned short version;
|
||||
unsigned long sectors_per_cluster;
|
||||
unsigned long bytes_per_sector;
|
||||
unsigned long free_clusters;
|
||||
unsigned long total_clusters;
|
||||
unsigned long available_physical_sectors;
|
||||
unsigned long total_physical_sectors;
|
||||
unsigned long free_allocation_units;
|
||||
unsigned long total_allocation_units;
|
||||
unsigned char reserved[8];
|
||||
} FAT32_Free_Space;
|
||||
|
||||
if (!drive) _dos_getdrive(&drive); /* use current drive */
|
||||
/* Note: RBIL carry clear and al==0 also means unimplemented
|
||||
alternately carry set and ax==undefined (usually unchanged) for unimplemented
|
||||
ecm: RBIL is wrong, CF unchanged al=0 is the typical error return.
|
||||
EDR-DOS returns NC ax=0 so checking for al!=0 here was wrong.
|
||||
*/
|
||||
rootname[0] = 'A' + drive - 1;
|
||||
/* printf("Looking at drive [%s]\n", rootname); */
|
||||
r.w.cflag = 1; /* CY before 21.73 calls! */
|
||||
r.w.ax = 0x7303;
|
||||
s.ds = FP_SEG(rootname);
|
||||
r.w.dx = FP_OFF(rootname);
|
||||
s.es = FP_SEG(&FAT32_Free_Space);
|
||||
r.w.di = FP_OFF(&FAT32_Free_Space);
|
||||
r.w.cx = sizeof(FAT32_Free_Space);
|
||||
intdosx( &r, &r, &s );
|
||||
|
||||
/* see if call supported, if not then fallback to older get disk free API call */
|
||||
/* Note: from RBIL returning AL=0 (with carry unchanged/clear) means unimplemented,
|
||||
in such cases AH is unchanged, so will AH will still by 0x73, i.e. returning AX=0x7300
|
||||
EDR kernel returns with AX=0 if successful so error must check AX=7300 instead of just AL for 0
|
||||
FreeDOS kernel returns with AX unchanged, i.e. 0x7303 on success
|
||||
If returns carry set then AX is undefined, but an error.
|
||||
(carry OR (AX == 0x7300)) indicates error, so we check for NOT (carry OR (AX == 0x7300))
|
||||
*/
|
||||
if (!(r.w.cflag & 0x01) && (r.w.ax != 0x7300)) /* call available and successfully returned */
|
||||
{
|
||||
/* calculate free space, but handle some overflow cases (or switch to 64bit values) */
|
||||
if (clustersize != NULL) *clustersize = FAT32_Free_Space.sectors_per_cluster * FAT32_Free_Space.bytes_per_sector;
|
||||
if (free_clusters != NULL) *free_clusters = FAT32_Free_Space.free_clusters;
|
||||
|
||||
/* total free is cluster size * # of free clusters */
|
||||
#if 0
|
||||
if (clustersize)
|
||||
{
|
||||
/* if (MAX_ULONG / operand1) < operand2 then will overflow (operand1 * operand2 > MAX_ULONG */
|
||||
if ((4294967295ul / clustersize) < FAT32_Free_Space.free_clusters) {
|
||||
freesize = (unsigned long)-1; /* max size */
|
||||
} else {
|
||||
freesize = clustersize * FAT32_Free_Space.free_clusters;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else /* ((r.w.cflag & 0x01) || (!r.h.al)) */
|
||||
{
|
||||
static struct dfree disktable;
|
||||
getdfree(drive, &disktable);
|
||||
if (clustersize != NULL) *clustersize = (unsigned long) disktable.df_bsec * disktable.df_sclus;
|
||||
if (free_clusters != NULL) *free_clusters = disktable.df_avail;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/* Works like function strcpy() but stops copying characters into */
|
||||
@ -364,6 +462,35 @@ int datevalid(THEDATE * dt) {
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/* Copies argument into buffer until new option or end of string found. */
|
||||
/*-------------------------------------------------------------------------*/
|
||||
static char option_buffer[1024];
|
||||
static char * get_option(const char **next_argptr, unsigned *count)
|
||||
{
|
||||
unsigned int i, tmp_maxlen;
|
||||
const char *src = *next_argptr+1; /* +1 skip past option char (/ or -) */
|
||||
char *dest = option_buffer+*count;
|
||||
int expecting_date = 0; /* flag indicating / may be part of option */
|
||||
|
||||
tmp_maxlen = sizeof(option_buffer) - (*count) - 1;
|
||||
i = 0;
|
||||
while ((src[i] != '\0') &&
|
||||
(i < tmp_maxlen) &&
|
||||
((!expecting_date && ((src[i] != '-') && (src[i] != '/'))) || expecting_date))
|
||||
{
|
||||
dest[i] = src[i];
|
||||
expecting_date |= src[i] == ':'; /* currently only /D:<date> option */
|
||||
i++;
|
||||
}
|
||||
dest[i] = '\0';
|
||||
if (i >= tmp_maxlen) *next_argptr = dest+i; /* ensure points to '\0' */
|
||||
else *next_argptr = src+i;
|
||||
*count += i + 1;
|
||||
return dest;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/* Splits the program arguments into file and switch arguments. */
|
||||
/*-------------------------------------------------------------------------*/
|
||||
@ -375,6 +502,8 @@ void classify_args(const int argc,
|
||||
char **switchargv) {
|
||||
int i;
|
||||
char *argptr;
|
||||
unsigned count = 0;
|
||||
const char *next_argptr;
|
||||
|
||||
|
||||
*fileargc = 0;
|
||||
@ -383,8 +512,13 @@ void classify_args(const int argc,
|
||||
argptr = (char *)argv[i];
|
||||
if (argptr[0] == '/' || argptr[0] == '-') {
|
||||
/* first character of parameter is '/' or '-' -> switch argument */
|
||||
switchargv[*switchargc] = argptr + 1;
|
||||
//switchargv[*switchargc] = argptr + 1;
|
||||
next_argptr = argptr;
|
||||
do {
|
||||
switchargv[*switchargc] = get_option(&next_argptr, &count);
|
||||
/* printf("switcharg[%i]=|%s|\n", *switchargc, switchargv[*switchargc]); */
|
||||
*switchargc = *switchargc + 1;
|
||||
} while (*next_argptr != '\0');
|
||||
}
|
||||
else {
|
||||
/* file argument */
|
||||
@ -513,17 +647,13 @@ char confirm(const char *msg,
|
||||
/*-------------------------------------------------------------------------*/
|
||||
void copy_file(const char *src_filename,
|
||||
const char *dest_filename,
|
||||
const char return_on_error,
|
||||
const char keep_attrib,
|
||||
const char reset_arch) {
|
||||
const char return_on_error) {
|
||||
FILE *src_file,
|
||||
*dest_file;
|
||||
char buffer[16384];
|
||||
static char buffer[16384]; /* don't put buffer on stack! */
|
||||
unsigned int buffersize;
|
||||
int readsize,
|
||||
fileattrib;
|
||||
struct ftime filetime;
|
||||
|
||||
|
||||
/* open source file */
|
||||
src_file = fopen(src_filename, "rb");
|
||||
@ -568,62 +698,14 @@ void copy_file(const char *src_filename,
|
||||
readsize = fread(buffer, sizeof(char), buffersize, src_file);
|
||||
}
|
||||
|
||||
/* copy file timestamp */
|
||||
getftime(fileno(src_file), &filetime);
|
||||
setftime(fileno(dest_file), &filetime);
|
||||
|
||||
/* close files */
|
||||
fclose(src_file);
|
||||
fclose(dest_file);
|
||||
|
||||
/* update timestamp after completing copy to ensure OS actually sets to original date and not current time */
|
||||
os_setftime(src_filename, dest_filename);
|
||||
|
||||
/* copy file attributes */
|
||||
fileattrib = _chmod(src_filename, 0);
|
||||
if(!keep_attrib) {
|
||||
fileattrib = fileattrib & FA_ARCH;
|
||||
}
|
||||
if(reset_arch){
|
||||
fileattrib = fileattrib & !FA_ARCH;
|
||||
}
|
||||
_chmod(dest_filename, 1, fileattrib);
|
||||
}
|
||||
|
||||
unsigned int getDOSVersion() {
|
||||
union REGS regs;
|
||||
|
||||
regs.h.ah = 0x30; // Function code for get DOS version
|
||||
intdos(®s, ®s);
|
||||
|
||||
// AL register will contain the DOS major version
|
||||
// AH register will contain the DOS minor version
|
||||
if (regs.h.al == 0) {
|
||||
regs.h.al++;
|
||||
}
|
||||
return (regs.h.al << 8) | regs.h.ah;
|
||||
}
|
||||
|
||||
unsigned int get_extendedDiskInfo (char driveNumber, struct DiskInfo *diskInfo) {
|
||||
union REGS regs;
|
||||
struct SREGS segregs;
|
||||
char driveString[4];
|
||||
|
||||
if(driveNumber < 1 || driveNumber > 26) return 0xFFFF;
|
||||
|
||||
// Set up buffer for result
|
||||
segread(&segregs); /* Get the segment of DS */
|
||||
regs.x.di = FP_OFF(diskInfo);
|
||||
segregs.es = FP_SEG(diskInfo);
|
||||
|
||||
// Convert drive number to ASCIZ string
|
||||
sprintf(driveString, "%c:\\", 'A' + driveNumber - 1);
|
||||
|
||||
// Set up registers
|
||||
regs.h.ah = 0x73; /* Function code for get free disk space */
|
||||
regs.h.al = 0x03; /* Sub-function code for get disk information */
|
||||
regs.x.cx = sizeof(struct DiskInfo);
|
||||
regs.x.dx = FP_OFF(driveString);
|
||||
segregs.ds = FP_SEG(driveString);
|
||||
|
||||
// Perform the interrupt
|
||||
intdosx(®s, ®s, &segregs);
|
||||
return regs.x.ax;
|
||||
}
|
||||
|
@ -25,9 +25,6 @@
|
||||
/* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
/***************************************************************************/
|
||||
|
||||
/* Downloaded original source from the following link and fixed attribute copy */
|
||||
/* https://github.com/FDOS/xcopy/commit/71dd94271057b3a60c6a01d1c3f2c7da856c464c */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
@ -47,7 +44,7 @@ nl_catd cat; /* message catalog, must be before shared.inc */
|
||||
|
||||
#if defined(__TURBOC__) && !defined(__BORLANDC__)
|
||||
#define _splitpath fnsplit
|
||||
void _fullpath_tc(char * truename, char * rawname, unsigned int namelen)
|
||||
void _fullpath(char * truename, char * rawname, unsigned int namelen)
|
||||
{
|
||||
union REGS regs;
|
||||
struct SREGS sregs;
|
||||
@ -102,13 +99,20 @@ char switch_archive = 0,
|
||||
switch_verify = 0,
|
||||
switch_wait = 0,
|
||||
bak_verify = 0,
|
||||
switch_keep_attr = 0,
|
||||
dest_drive;
|
||||
long int switch_date = 0;
|
||||
long file_counter = 0;
|
||||
int file_found = 0;
|
||||
|
||||
|
||||
/* these are only used by xcopy_files, built up as recurse deeper into
|
||||
into subdirectory to help avoid overflowing stack with each
|
||||
recursive call */
|
||||
char new_src_pathname[MAXPATH];
|
||||
char new_dest_pathname[MAXPATH];
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/* PROTOTYPES */
|
||||
/*-------------------------------------------------------------------------*/
|
||||
@ -129,7 +133,7 @@ void xcopy_files(const char *src_pathname,
|
||||
const char *dest_filename);
|
||||
void xcopy_file(const char *src_filename,
|
||||
const char *dest_filename);
|
||||
unsigned int getDOSVersion(void);
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/* MAIN-PROGRAM */
|
||||
@ -149,11 +153,7 @@ int main(int argc, const char **argv) {
|
||||
ch;
|
||||
int i, length;
|
||||
THEDATE dt;
|
||||
#ifdef __WATCOMC__
|
||||
struct dostime_t tm;
|
||||
#else
|
||||
struct time tm;
|
||||
#endif
|
||||
THETIME tm;
|
||||
|
||||
cat = catopen ("xcopy", 0); /* initialize kitten */
|
||||
|
||||
@ -207,13 +207,9 @@ int main(int argc, const char **argv) {
|
||||
catclose(cat);
|
||||
exit(4);
|
||||
}
|
||||
#ifdef __WATCOMC__
|
||||
memset((void *)&tm, 0, sizeof(struct dostime_t));
|
||||
/* tm.tm_hour = 0; tm.tm_min = 0; tm.tm_sec = 0; tm.tm_hund = 0; */
|
||||
#else
|
||||
memset((void *)&tm, 0, sizeof(struct time));
|
||||
/* tm.ti_hour = 0; tm.ti_min = 0; tm.ti_sec = 0; tm.ti_hund = 0; */
|
||||
#endif
|
||||
memset((void *)&tm, 0, sizeof(THETIME));
|
||||
/* tm.tm_hour = 0; tm.tm_min = 0; tm.tm_sec = 0; tm.tm_hund = 0; -- __WATCOM__ */
|
||||
/* tm.ti_hour = 0; tm.ti_min = 0; tm.ti_sec = 0; tm.ti_hund = 0; -- all others */
|
||||
switch_date = dostounix(&dt, &tm);
|
||||
}
|
||||
else if (strcmp(tmp_switch, "E") == 0)
|
||||
@ -224,8 +220,6 @@ int main(int argc, const char **argv) {
|
||||
switch_hidden = -1;
|
||||
else if (strcmp(tmp_switch, "I") == 0)
|
||||
switch_intodir = -1;
|
||||
else if (strcmp(tmp_switch, "K") == 0)
|
||||
switch_keep_attr = -1;
|
||||
else if (strcmp(tmp_switch, "L") == 0)
|
||||
switch_listmode = -1;
|
||||
else if (strcmp(tmp_switch, "M") == 0)
|
||||
@ -267,11 +261,7 @@ int main(int argc, const char **argv) {
|
||||
catclose(cat);
|
||||
exit(4);
|
||||
}
|
||||
#if defined(__TURBOC__) && !defined(__BORLANDC__)
|
||||
_fullpath_tc(src_pathname, fileargv[0], MYMAXPATH);
|
||||
#else
|
||||
_fullpath(src_pathname, fileargv[0], MYMAXPATH);
|
||||
#endif
|
||||
if (src_pathname[0] == '\0') {
|
||||
printf("%s\n", catgets(cat, 1, 5, "Invalid source drive specification"));
|
||||
catclose(cat);
|
||||
@ -317,11 +307,7 @@ int main(int argc, const char **argv) {
|
||||
catclose(cat);
|
||||
exit(4);
|
||||
}
|
||||
#if defined(__TURBOC__) && !defined(__BORLANDC__)
|
||||
_fullpath_tc(dest_pathname, fileargv[1], MYMAXPATH);
|
||||
#else
|
||||
_fullpath(dest_pathname, fileargv[1], MYMAXPATH);
|
||||
#endif
|
||||
if (dest_pathname[0] == '\0') {
|
||||
printf("%s\n", catgets(cat, 1, 9, "Invalid destination drive specification"));
|
||||
catclose(cat);
|
||||
@ -399,6 +385,8 @@ int main(int argc, const char **argv) {
|
||||
fflush(stdin);
|
||||
}
|
||||
|
||||
strmcpy(new_src_pathname, src_pathname, sizeof(new_src_pathname));
|
||||
strmcpy(new_dest_pathname, dest_pathname, sizeof(new_dest_pathname));
|
||||
xcopy_files(src_pathname, src_filename, dest_pathname, dest_filename);
|
||||
if (!file_found) {
|
||||
printf("%s - %s\n",catgets(cat, 1, 18, "File not found"), src_filename);
|
||||
@ -415,7 +403,7 @@ int main(int argc, const char **argv) {
|
||||
/* SUB-PROGRAMS */
|
||||
/*-------------------------------------------------------------------------*/
|
||||
void print_help(void) {
|
||||
printf("XCOPY v1.5 - Copyright 2001-2003 by Rene Ableidinger (patches 2005: Eric Auer)\n");
|
||||
printf("XCOPY v1.9a - Copyright 2001-2003 by Rene Ableidinger (patches 2005: Eric Auer)\n");
|
||||
/* VERSION! */
|
||||
printf("%s\n\n", catgets(cat, 2, 1, "Copies files and directory trees."));
|
||||
printf("%s\n\n", catgets(cat, 2, 2, "XCOPY source [destination] [/switches]"));
|
||||
@ -432,32 +420,31 @@ void print_help(void) {
|
||||
printf("%s\n", catgets(cat, 2, 13, " /H Copies hidden and system files as well as unprotected files."));
|
||||
printf("%s\n", catgets(cat, 2, 14, " /I If destination does not exist and copying more than one file,"));
|
||||
printf("%s\n", catgets(cat, 2, 15, " assume destination is a directory."));
|
||||
printf("%s\n", catgets(cat, 2, 16, " /K Keep attributes. Otherwise only archive attribute is copied."));
|
||||
printf("%s\n", catgets(cat, 2, 17, " /L List files without copying them. (simulates copying)"));
|
||||
printf("%s\n", catgets(cat, 2, 18, " /M Copies only files with the archive attribute set and turns off"));
|
||||
printf("%s\n", catgets(cat, 2, 16, " /L List files without copying them. (simulates copying)"));
|
||||
printf("%s\n", catgets(cat, 2, 17, " /M Copies only files with the archive attribute set and turns off"));
|
||||
printf("%s\n", catgets(cat, 2, 18, " the archive attribute of the source files after copying them."));
|
||||
|
||||
if (isatty(1)) {
|
||||
printf("-- %s --", catgets(cat, 2, 35, "press enter for more"));
|
||||
(void)getchar();
|
||||
} /* wait for next page if TTY */
|
||||
|
||||
printf("%s\n", catgets(cat, 2, 19, " the archive attribute of the source files after copying them."));
|
||||
printf("%s\n", catgets(cat, 2, 20, " /N Suppresses prompting to confirm you want to overwrite an"));
|
||||
printf("%s\n", catgets(cat, 2, 21, " existing destination file and skips these files."));
|
||||
printf("%s\n", catgets(cat, 2, 22, " /P Prompts for confirmation before creating each destination file."));
|
||||
printf("%s\n", catgets(cat, 2, 23, " /Q Quiet mode, don't show copied filenames."));
|
||||
printf("%s\n", catgets(cat, 2, 24, " /R Overwrite read-only files as well as unprotected files."));
|
||||
printf("%s\n", catgets(cat, 2, 25, " /S Copies directories and subdirectories except empty ones."));
|
||||
printf("%s\n", catgets(cat, 2, 26, " /T Creates directory tree without copying files. Empty directories"));
|
||||
printf("%s\n", catgets(cat, 2, 27, " will not be copied. To copy them add switch /E."));
|
||||
printf("%s\n", catgets(cat, 2, 28, " /V Verifies each new file."));
|
||||
printf("%s\n", catgets(cat, 2, 29, " /W Waits for a keypress before beginning."));
|
||||
printf("%s\n", catgets(cat, 2, 30, " /Y Suppresses prompting to confirm you want to overwrite an"));
|
||||
printf("%s\n", catgets(cat, 2, 31, " existing destination file and overwrites these files."));
|
||||
printf("%s\n", catgets(cat, 2, 32, " /-Y Causes prompting to confirm you want to overwrite an existing"));
|
||||
printf("%s\n\n", catgets(cat, 2, 33, " destination file."));
|
||||
printf("%s\n", catgets(cat, 2, 34, "The switch /Y or /N may be preset in the COPYCMD environment variable."));
|
||||
printf("%s\n", catgets(cat, 2, 35, "This may be overridden with /-Y on the command line."));
|
||||
printf("%s\n", catgets(cat, 2, 19, " /N Suppresses prompting to confirm you want to overwrite an"));
|
||||
printf("%s\n", catgets(cat, 2, 20, " existing destination file and skips these files."));
|
||||
printf("%s\n", catgets(cat, 2, 21, " /P Prompts for confirmation before creating each destination file."));
|
||||
printf("%s\n", catgets(cat, 2, 22, " /Q Quiet mode, don't show copied filenames."));
|
||||
printf("%s\n", catgets(cat, 2, 23, " /R Overwrite read-only files as well as unprotected files."));
|
||||
printf("%s\n", catgets(cat, 2, 24, " /S Copies directories and subdirectories except empty ones."));
|
||||
printf("%s\n", catgets(cat, 2, 25, " /T Creates directory tree without copying files. Empty directories"));
|
||||
printf("%s\n", catgets(cat, 2, 26, " will not be copied. To copy them add switch /E."));
|
||||
printf("%s\n", catgets(cat, 2, 27, " /V Verifies each new file."));
|
||||
printf("%s\n", catgets(cat, 2, 28, " /W Waits for a keypress before beginning."));
|
||||
printf("%s\n", catgets(cat, 2, 29, " /Y Suppresses prompting to confirm you want to overwrite an"));
|
||||
printf("%s\n", catgets(cat, 2, 30, " existing destination file and overwrites these files."));
|
||||
printf("%s\n", catgets(cat, 2, 31, " /-Y Causes prompting to confirm you want to overwrite an existing"));
|
||||
printf("%s\n\n", catgets(cat, 2, 32, " destination file."));
|
||||
printf("%s\n", catgets(cat, 2, 33, "The switch /Y or /N may be preset in the COPYCMD environment variable."));
|
||||
printf("%s\n", catgets(cat, 2, 34, "This may be overridden with /-Y on the command line."));
|
||||
}
|
||||
|
||||
|
||||
@ -609,48 +596,55 @@ void build_name(char *dest,
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/* Searches through the source directory (and its subdirectories) and calls */
|
||||
/* Searchs through the source directory (and its subdirectories) and calls */
|
||||
/* function "xcopy_file" for every found file. */
|
||||
/*-------------------------------------------------------------------------*/
|
||||
void xcopy_files(const char *src_pathname,
|
||||
const char *src_filename,
|
||||
const char *dest_pathname,
|
||||
const char *dest_filename) {
|
||||
char filepattern[MAXPATH],
|
||||
new_src_pathname[MAXPATH],
|
||||
new_dest_pathname[MAXPATH],
|
||||
src_path_filename[MAXPATH],
|
||||
dest_path_filename[MAXPATH],
|
||||
tmp_filename[MAXFILE + MAXEXT],
|
||||
tmp_pathname[MAXPATH];
|
||||
char src_path_filename[MAXPATH],
|
||||
dest_path_filename[MAXPATH];
|
||||
struct ffblk fileblock;
|
||||
int fileattrib,
|
||||
done;
|
||||
|
||||
/* WARNING these path values are overwritten on recursive calls */
|
||||
static char filepattern[MAXPATH],
|
||||
tmp_filename[MAXFILE + MAXEXT],
|
||||
tmp_pathname[MAXPATH];
|
||||
|
||||
if (switch_emptydir ||
|
||||
switch_subdir ||
|
||||
switch_tree) {
|
||||
/* store current path in static variable, append path to it and revert back after copy */
|
||||
char *end_new_src_pathname = new_src_pathname + strlen(new_src_pathname);
|
||||
char *end_new_dest_pathname = new_dest_pathname + strlen(new_dest_pathname);
|
||||
/* copy files in subdirectories too */
|
||||
|
||||
strmcpy(filepattern, src_pathname, sizeof(filepattern));
|
||||
strmcat(filepattern, "*.*", sizeof(filepattern));
|
||||
done = findfirst(filepattern, &fileblock, FA_DIREC);
|
||||
|
||||
while (!done) {
|
||||
if ((fileblock.ff_attrib & FA_DIREC) != 0 &&
|
||||
strcmp(fileblock.ff_name, ".") != 0 &&
|
||||
strcmp(fileblock.ff_name, "..") != 0) {
|
||||
/* build source pathname */
|
||||
strmcpy(new_src_pathname, src_pathname, sizeof(new_src_pathname));
|
||||
strmcat(new_src_pathname, fileblock.ff_name, sizeof(new_src_pathname));
|
||||
strmcat(new_src_pathname, DIR_SEPARATOR, sizeof(new_src_pathname));
|
||||
/*strmcpy(new_src_pathname, src_pathname, sizeof(new_src_pathname));*/
|
||||
strmcat(end_new_src_pathname, fileblock.ff_name, sizeof(new_src_pathname));
|
||||
strmcat(end_new_src_pathname, DIR_SEPARATOR, sizeof(new_src_pathname));
|
||||
|
||||
/* build destination pathname */
|
||||
strmcpy(new_dest_pathname, dest_pathname, sizeof(new_dest_pathname));
|
||||
strmcat(new_dest_pathname, fileblock.ff_name, sizeof(new_dest_pathname));
|
||||
strmcat(new_dest_pathname, DIR_SEPARATOR, sizeof(new_dest_pathname));
|
||||
/*strmcpy(new_dest_pathname, dest_pathname, sizeof(new_dest_pathname));*/
|
||||
strmcat(end_new_dest_pathname, fileblock.ff_name, sizeof(new_dest_pathname));
|
||||
strmcat(end_new_dest_pathname, DIR_SEPARATOR, sizeof(new_dest_pathname));
|
||||
|
||||
xcopy_files(new_src_pathname, src_filename,
|
||||
new_dest_pathname, dest_filename);
|
||||
|
||||
|
||||
*end_new_src_pathname = '\0';
|
||||
*end_new_dest_pathname = '\0';
|
||||
}
|
||||
|
||||
done = findnext(&fileblock);
|
||||
@ -674,7 +668,7 @@ void xcopy_files(const char *src_pathname,
|
||||
|
||||
/* check if destination directory must be created */
|
||||
if ((!done || switch_emptydir) &&
|
||||
!dir_exists(dest_pathname)) {
|
||||
!dir_exists(dest_pathname) && !switch_listmode) {
|
||||
strmcpy(tmp_pathname, dest_pathname, sizeof(tmp_pathname));
|
||||
if (make_dir(tmp_pathname) != 0) {
|
||||
printf("%s %s\n", catgets(cat, 1, 20, "Unable to create directory"), tmp_pathname);
|
||||
@ -714,27 +708,22 @@ void xcopy_files(const char *src_pathname,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/* Checks all dependencies of the source and destination file and calls */
|
||||
/* function "copy_file". */
|
||||
/*-------------------------------------------------------------------------*/
|
||||
void xcopy_file(const char *src_filename,
|
||||
const char *dest_filename) {
|
||||
static char msg_prompt[256];
|
||||
static struct stat src_statbuf;
|
||||
static struct stat dest_statbuf;
|
||||
static unsigned long cluster_size; /* in bytes */
|
||||
static unsigned long free_clusters; /* count of clusters */
|
||||
int dest_file_exists;
|
||||
int fileattrib;
|
||||
struct stat src_statbuf;
|
||||
struct stat dest_statbuf;
|
||||
#if defined(__TURBOC__) && !defined(__BORLANDC__)
|
||||
struct diskfree_t disk;
|
||||
#else
|
||||
struct dfree disktable;
|
||||
#endif
|
||||
unsigned long free_diskspace = -1;
|
||||
unsigned long bsec = 512;
|
||||
char ch;
|
||||
char msg_prompt[255];
|
||||
unsigned int dos_version = 0;
|
||||
struct DiskInfo diskinfo;
|
||||
|
||||
|
||||
if (switch_prompt) {
|
||||
/* ask for confirmation to create file */
|
||||
@ -755,7 +744,7 @@ void xcopy_file(const char *src_filename,
|
||||
}
|
||||
|
||||
/* check source file for read permission */
|
||||
/* (only useful under an OS with the ability to deny read access) */
|
||||
/* (only usefull under an OS with the ability to deny read access) */
|
||||
if (access(src_filename, R_OK) != 0) {
|
||||
printf("%s - %s\n", catgets(cat, 1, 22, "Read access denied"), src_filename);
|
||||
if (switch_continue) {
|
||||
@ -771,55 +760,25 @@ void xcopy_file(const char *src_filename,
|
||||
stat((char *)src_filename, &src_statbuf);
|
||||
dest_file_exists = !stat((char *)dest_filename, &dest_statbuf);
|
||||
|
||||
dos_version = getDOSVersion();
|
||||
/* get amount of free disk space in destination drive (in clusters not bytes) */
|
||||
getdiskfreeclusters(dest_drive, &cluster_size, &free_clusters);
|
||||
|
||||
/* get amount of free disk space in destination drive */
|
||||
if(((dos_version >> 8) > 7) || (((dos_version >> 8) == 7) && ((dos_version & 0xFF) >= 10))){
|
||||
//printf("%d %s", dest_drive, dest_drive);
|
||||
if(!get_extendedDiskInfo(dest_drive, &diskinfo)){
|
||||
bsec = diskinfo.bytesPerSector;
|
||||
free_diskspace = diskinfo.availableClusters * diskinfo.sectorsPerCluster;
|
||||
//printf("free_diskspace=%lu avail_clusters=%lu,sectors_per_cluster=%lu \n", free_diskspace, diskinfo.availableClusters, diskinfo.sectorsPerCluster);
|
||||
}
|
||||
else {
|
||||
goto int21_36h; /* Try the old DOS method if failed */
|
||||
}
|
||||
}
|
||||
else {
|
||||
int21_36h:
|
||||
#if defined(__TURBOC__) && !defined(__BORLANDC__)
|
||||
if(_dos_getdiskfree(dest_drive, &disk) != 0) {
|
||||
printf("Failed to obtain free disk space. Aborting\n");
|
||||
exit(39);
|
||||
}
|
||||
bsec = disk.bytes_per_sector;
|
||||
free_diskspace = (unsigned long) disk.avail_clusters * disk.sectors_per_cluster;
|
||||
//printf("dest_drive=%d,free_diskspace=%lu avail_clusters=%u,sectors_per_cluster=%u \n",dest_drive, free_diskspace, disk.avail_clusters, disk.sectors_per_cluster);
|
||||
#else
|
||||
getdfree(dest_drive, &disktable);
|
||||
bsec = disktable.df_bsec;
|
||||
free_diskspace = (unsigned long) disktable.df_avail * disktable.df_sclus;
|
||||
//printf("disktable.df_avail=%d,disktable.df_sclus=%d\n",disktable.df_avail * disktable.df_sclus);
|
||||
//free_diskspace = (unsigned long) disktable.df_avail *
|
||||
// (unsigned long) disktable.df_sclus *
|
||||
// (unsigned long) disktable.df_bsec;
|
||||
#endif
|
||||
}
|
||||
if (dest_file_exists) {
|
||||
if (switch_date) {
|
||||
if (switch_date < 0) {
|
||||
/* check, that only newer files are copied */
|
||||
if (src_statbuf.st_mtime <= dest_statbuf.st_mtime) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* only copy files newer than requested date */
|
||||
/* -1 =if exists then only copy newer, 0=copy regardless of date, >0 date to compare if newer */
|
||||
if (switch_date > 0) {
|
||||
/* check, that only files changed on or after the specified date */
|
||||
/* are copied */
|
||||
if (src_statbuf.st_mtime < switch_date) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (dest_file_exists) {
|
||||
if (switch_date < 0) {
|
||||
/* check, that only newer files are copied */
|
||||
if (src_statbuf.st_mtime <= dest_statbuf.st_mtime) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
switch (switch_confirm) {
|
||||
@ -854,9 +813,11 @@ int21_36h:
|
||||
}
|
||||
|
||||
/* check free space on destination disk */
|
||||
/* *** was wrong, was: "if (src... > free... - dest...) ..." */
|
||||
/* Note: if existing file is larger than current then always room for new file even if drive is full;
|
||||
otherwise need to ensure enough free clusters to support additional file size (additional clusters).
|
||||
*/
|
||||
if ( (src_statbuf.st_size > dest_statbuf.st_size) &&
|
||||
(((src_statbuf.st_size - dest_statbuf.st_size) / bsec) > free_diskspace) ) {
|
||||
((((src_statbuf.st_size - dest_statbuf.st_size) + (cluster_size-1))/cluster_size) > free_clusters) ) {
|
||||
printf("%s - %s\n", catgets(cat, 1, 23, "Insufficient disk space in destination path"), dest_filename);
|
||||
catclose(cat);
|
||||
exit(39);
|
||||
@ -888,10 +849,11 @@ int21_36h:
|
||||
}
|
||||
else {
|
||||
/* check free space on destination disk */
|
||||
unsigned long st_size_sec = (unsigned long)src_statbuf.st_size / bsec;
|
||||
/* Note: files are stored in clusters, so we check if enough free clusters,
|
||||
but we do this to avoid overflow of 32bit integers if freespace > 4GB
|
||||
*/
|
||||
|
||||
if (st_size_sec > (unsigned long)free_diskspace) {
|
||||
printf("%lu - %lu\n", st_size_sec, free_diskspace);
|
||||
if (((src_statbuf.st_size + (cluster_size-1))/cluster_size) > free_clusters) {
|
||||
printf("%s - %s\n", catgets(cat, 1, 25, "Insufficient disk space in destination path"), dest_filename);
|
||||
catclose(cat);
|
||||
exit(39);
|
||||
@ -910,7 +872,15 @@ int21_36h:
|
||||
|
||||
/* check, if file copying should be simulated */
|
||||
if (!switch_listmode) {
|
||||
copy_file(src_filename, dest_filename, switch_continue, switch_keep_attr, switch_archive_reset);
|
||||
copy_file(src_filename, dest_filename, switch_continue);
|
||||
fileattrib = _chmod(dest_filename, 0);
|
||||
_chmod(dest_filename, 1, fileattrib & FA_ARCH);
|
||||
|
||||
if (switch_archive_reset) {
|
||||
/* remove archive attribute from source file */
|
||||
fileattrib = _chmod(src_filename, 0);
|
||||
_chmod(src_filename, 1, fileattrib ^ FA_ARCH);
|
||||
}
|
||||
}
|
||||
|
||||
file_counter++;
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user