Replace xcopy source files with ver. 1.9a

This commit is contained in:
maron2000 2025-04-14 20:52:30 +09:00
parent 62c118932f
commit 0e385cbeb7
3 changed files with 275 additions and 218 deletions

View File

@ -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)

View File

@ -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;
*switchargc = *switchargc + 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(&regs, &regs);
// 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(&regs, &regs, &segregs);
return regs.x.ax;
}

View File

@ -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,54 +760,24 @@ 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
/* 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) {
if (switch_date < 0) {
/* check, that only newer files are copied */
if (src_statbuf.st_mtime <= dest_statbuf.st_mtime) {
return;
}
}
else {
/* check, that only files changed on or after the specified date */
/* are copied */
if (src_statbuf.st_mtime < switch_date) {
return;
}
if (switch_date < 0) {
/* check, that only newer files are copied */
if (src_statbuf.st_mtime <= dest_statbuf.st_mtime) {
return;
}
}
@ -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;
if (st_size_sec > (unsigned long)free_diskspace) {
printf("%lu - %lu\n", st_size_sec, free_diskspace);
/* 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 (((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,13 @@ 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);
if (switch_archive_reset) {
/* remove archive attribute from source file */
fileattrib = _chmod(src_filename, 0);
_chmod(src_filename, 1, fileattrib ^ FA_ARCH);
}
}
file_counter++;