Changed copy() to use a two pass algorithm: Now SYS first calls

copy to read kernel and command.com into RAM, then updates the
boot sector, then calls copy again to write kernel and command
from RAM to disk. This reduces disk changes a lot when you do
SYS A: B: on a PC which only has 1 diskette drive ("DJ style").


git-svn-id: https://svn.code.sf.net/p/freedos/svn/kernel/trunk@1349 6ac86273-5f31-0410-b378-82cca8765d1b
This commit is contained in:
Eric Auer 2007-08-27 00:23:38 +00:00
parent 94d0560e7b
commit 94085ce923

279
sys/sys.c
View File

@ -29,7 +29,7 @@
#define DEBUG #define DEBUG
/* #define DDEBUG */ /* #define DDEBUG */
#define SYS_VERSION "v3.2" #define SYS_VERSION "v3.3"
#include <stdlib.h> #include <stdlib.h>
#include <dos.h> #include <dos.h>
@ -40,6 +40,7 @@
#include <mem.h> #include <mem.h>
#else #else
#include <memory.h> #include <memory.h>
#include <malloc.h> /* fmalloc() in open watcom */
#endif #endif
#include <string.h> #include <string.h>
#ifdef __TURBOC__ #ifdef __TURBOC__
@ -161,7 +162,8 @@ BYTE pgm[] = "SYS";
void put_boot(int, char *, char *, int, int); void put_boot(int, char *, char *, int, int);
BOOL check_space(COUNT, ULONG); BOOL check_space(COUNT, ULONG);
BOOL copy(COUNT drive, BYTE * srcPath, BYTE * rootPath, BYTE * file); BYTE far * copy(COUNT drive, BYTE * srcPath, BYTE * rootPath,
BYTE * file, BYTE far * buffer, ULONG * filesize);
#define SEC_SIZE 512 #define SEC_SIZE 512
#define COPY_SIZE 0x7e00 #define COPY_SIZE 0x7e00
@ -240,12 +242,61 @@ struct VerifyBootSectorSize {
int FDKrnConfigMain(int argc, char **argv); int FDKrnConfigMain(int argc, char **argv);
#ifndef __TURBOC__
#ifdef __WATCOMC__
/* int 21.48 takes a paragraph (16 byte units) count as input in bx */
/* ... int 21.48 returns the segment after the allocated MCB in ax */
void far * farmalloc( ULONG __size );
#pragma aux farmalloc = \
"shr cx, 1" \
"rcr bx, 1" \
"shr cx, 1" \
"rcr bx, 1" \
"shr cx, 1" \
"rcr bx, 1" \
"shr cx, 1" \
"rcr bx, 1" \
"inc bx" \
"xor dx, dx" \
"or cx, cx" \
"jnz nomalloc" \
"mov ax, 0x4800" \
"int 0x21" \
"jc nomalloc" \
"mov dx, ax" \
"nomalloc:" \
"xor ax, ax" \
parm [cx bx] \
modify [bx] \
value [dx ax];
void initalloc( void );
#pragma aux initalloc = \
"push es" \
"mov ax, cs" \
"mov es, ax" \
"mov bx, 0x1000" \
"mov ax, 0x4a00" \
"int 0x21" \
"pop es" \
modify [ax bx];
#endif
#endif
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
COUNT drive; /* destination drive */ COUNT drive; /* destination drive */
COUNT drivearg = 0; /* drive argument position */ COUNT drivearg = 0; /* drive argument position */
COUNT srcarg = 0; /* source argument position */ COUNT srcarg = 0; /* source argument position */
BYTE *bsFile = NULL; /* user specified destination boot sector */ BYTE *bsFile = NULL; /* user specified destination boot sector */
ULONG kernelsize = 0; /* size of the kernel to be copied */
BYTE far *kernelbuf = NULL; /* kernel to be copied */
ULONG shellsize = 0; /* size of the shell to be copied */
BYTE far *shellbuf = NULL; /* shell to be copied */
unsigned srcDrive; /* source drive */ unsigned srcDrive; /* source drive */
BYTE srcPath[SYS_MAXPATH]; /* user specified source drive and/or path */ BYTE srcPath[SYS_MAXPATH]; /* user specified source drive and/or path */
BYTE rootPath[4]; /* alternate source path to try if not '\0' */ BYTE rootPath[4]; /* alternate source path to try if not '\0' */
@ -256,6 +307,10 @@ int main(int argc, char **argv)
char *kernel_name = "KERNEL.SYS"; char *kernel_name = "KERNEL.SYS";
int load_segment = 0x60; int load_segment = 0x60;
#ifdef __WATCOMC__
initalloc(); /* reduce main MCB of .com file to 64 kB */
#endif
printf("FreeDOS System Installer " SYS_VERSION ", " __DATE__ "\n\n"); printf("FreeDOS System Installer " SYS_VERSION ", " __DATE__ "\n\n");
if (argc > 1 && memicmp(argv[1], "CONFIG", 6) == 0) if (argc > 1 && memicmp(argv[1], "CONFIG", 6) == 0)
@ -368,35 +423,54 @@ int main(int argc, char **argv)
else else
sprintf(rootPath, "%c:\\", 'A' + srcDrive); sprintf(rootPath, "%c:\\", 'A' + srcDrive);
printf("Processing boot sector...\n");
put_boot(drive, bsFile, kernel_name, load_segment, both);
if (!bootonly) if (!bootonly)
{ {
printf("\nCopying %s...\n", kernel_name); printf("Reading %s...\n", kernel_name);
if (!copy(drive, srcPath, rootPath, kernel_name)) kernelbuf = copy(drive, srcPath, rootPath, kernel_name, NULL, &kernelsize);
if (kernelbuf == NULL)
{ {
printf("\n%s: cannot copy \"%s\"\n", pgm, kernel_name); printf("\n%s: cannot read \"%s\"\n", pgm, kernel_name);
exit(1); exit(1);
} /* copy kernel */ } /* fetch kernel */
printf("\nReading COMMAND.COM...\n");
printf("\nCopying COMMAND.COM...\n"); shellbuf = copy(drive, srcPath, rootPath, "COMMAND.COM", NULL, &shellsize);
if (!copy(drive, srcPath, rootPath, "COMMAND.COM")) if (shellbuf == NULL)
{ {
char *comspec = getenv("COMSPEC"); char *comspec = getenv("COMSPEC");
if (comspec != NULL) if (comspec != NULL)
{ {
printf("%s: Trying \"%s\"\n", pgm, comspec); printf("%s: Trying \"%s\"\n", pgm, comspec);
if (!copy(drive, comspec, NULL, "COMMAND.COM")) shellbuf = copy(drive, comspec, NULL, "COMMAND.COM", NULL, &shellsize);
if (shellbuf == NULL)
comspec = NULL; comspec = NULL;
} }
if (comspec == NULL) if (comspec == NULL)
{ {
printf("\n%s: cannot copy \"COMMAND.COM\"\n", pgm); printf("\n%s: cannot read \"COMMAND.COM\"\n", pgm);
exit(1); exit(1);
} }
} /* copy shell */ } /* fetch shell */
} } /* file READS */
printf("\nProcessing boot sector...\n"); /* READ and WRITE */
put_boot(drive, bsFile, kernel_name, load_segment, both);
if (!bootonly)
{
printf("\nWriting %s...\n", kernel_name);
if (copy(drive, NULL, rootPath, kernel_name, kernelbuf, &kernelsize)==NULL)
{
printf("\n%s: cannot write \"%s\"\n", pgm, kernel_name);
exit(1);
} /* write kernel */
printf("\nWriting COMMAND.COM...\n");
if (copy(drive, NULL, rootPath, "COMMAND.COM", shellbuf, &shellsize)==NULL)
{
printf("\n%s: cannot write \"COMMAND.COM\"\n", pgm);
exit(1);
} /* write shell */
} /* file WRITES */
printf("\nSystem transferred.\n"); printf("\nSystem transferred.\n");
return 0; return 0;
@ -932,19 +1006,30 @@ BOOL check_space(COUNT drive, ULONG bytes)
BYTE copybuffer[COPY_SIZE]; BYTE copybuffer[COPY_SIZE];
BOOL copy(COUNT drive, BYTE * srcPath, BYTE * rootPath, BYTE * file) /* if buffer is NULL, read the file, set filesize, and return a buffer */
/* if buffer is not NULL, write, according to filesize, from buffer... */
BYTE far * copy(COUNT drive, BYTE * srcPath, BYTE * rootPath,
BYTE * file, BYTE far * buffer, ULONG * filesize)
{ {
static BYTE dest[SYS_MAXPATH], source[SYS_MAXPATH]; static BYTE dest[SYS_MAXPATH], source[SYS_MAXPATH];
unsigned ret; UWORD ret;
int fdin, fdout; int fdin, fdout;
ULONG copied = 0; ULONG copied = 0;
struct stat fstatbuf; struct stat fstatbuf;
BOOL reading = (buffer==NULL);
strcpy(source, srcPath); strcpy(source, srcPath);
if (rootPath != NULL) /* trick for comspec */ if (rootPath != NULL) /* trick for comspec */
strcat(source, file); strcat(source, file);
if (stat(source, &fstatbuf)) if (!reading && *filesize==0) /* write mode but no writing needed */
{
printf("%s: source and destination were identical: skipping \"%s\"\n",
pgm, source);
return buffer;
}
if (reading && stat(source, &fstatbuf)) /* read mode */
{ {
printf("%s: \"%s\" not found\n", pgm, source); printf("%s: \"%s\" not found\n", pgm, source);
@ -955,57 +1040,128 @@ BOOL copy(COUNT drive, BYTE * srcPath, BYTE * rootPath, BYTE * file)
if (stat(source, &fstatbuf)) if (stat(source, &fstatbuf))
{ {
printf("%s: \"%s\" not found\n", pgm, source); printf("%s: \"%s\" not found\n", pgm, source);
return FALSE; return NULL;
} }
} }
else else
return FALSE; return NULL;
} }
truename(dest, source); if (reading) /* if reading */
strcpy(source, dest);
sprintf(dest, "%c:\\%s", 'A' + drive, file);
if (stricmp(source, dest) == 0)
{ {
printf("%s: source and destination are identical: skipping \"%s\"\n", truename(dest, source); /* use dest as buffer for truename(source) */
pgm, source); strcpy(source, dest); /* write updated source string */
return TRUE; sprintf(dest, "%c:\\%s", 'A' + drive, file);
} if (stricmp(source, dest) == 0)
{
printf("%s: source and destination are identical: skipping \"%s\"\n",
pgm, source);
*filesize = 0; /* special size */
return (BYTE far *) 1; /* return something non-null */
}
if ((fdin = open(source, O_RDONLY | O_BINARY)) < 0) if ((fdin = open(source, O_RDONLY | O_BINARY)) < 0)
{
printf("%s: failed to open \"%s\"\n", pgm, source);
return NULL;
}
*filesize = filelength(fdin); /* return size */
} /* reading */
if (!reading) /* writing */
{ {
printf("%s: failed to open \"%s\"\n", pgm, source); if (!check_space(drive, *filesize))
return FALSE; {
} printf("%s: Not enough space to transfer %s\n", pgm, file);
/* close(fdin); */
/* exit(1); too pessimistic? we might overwrite a pre-existing file */
return NULL; /* still pessimistic, did not even try to overwrite... */
}
if (!check_space(drive, filelength(fdin))) sprintf(dest, "%c:\\%s", 'A' + drive, file);
{ if ((fdout =
printf("%s: Not enough space to transfer %s\n", pgm, file);
close(fdin);
exit(1);
}
if ((fdout =
open(dest, O_RDWR | O_TRUNC | O_CREAT | O_BINARY, open(dest, O_RDWR | O_TRUNC | O_CREAT | O_BINARY,
S_IREAD | S_IWRITE)) < 0) S_IREAD | S_IWRITE)) < 0)
{
printf(" %s: can't create\"%s\"\nDOS errnum %d", pgm, dest, errno);
close(fdin);
return FALSE;
}
while ((ret = read(fdin, copybuffer, COPY_SIZE)) > 0)
{
if (write(fdout, copybuffer, ret) != ret)
{ {
printf("Can't write %u bytes to %s\n", ret, dest); printf(" %s: can't create\"%s\"\nDOS errnum %d", pgm, dest, errno);
close(fdout); /* close(fdin); */
unlink(dest); return NULL;
break;
} }
copied += ret; } /* writing */
}
if (reading) /* reading */
{
BYTE far *bufptr;
#ifdef __TURBOC__ /* workaround: farmalloc is nearmalloc if tiny model in TC2 ?? */
UWORD theseg;
if (allocmem((*filesize+15)>>4, &theseg)!=-1) /* allocate dos memory */
#else
buffer = (BYTE far *)farmalloc(*filesize);
if (buffer==NULL)
#endif
{
printf("Not enough memory to buffer %lu bytes for %s\n", *filesize, source);
return NULL;
}
#ifdef __TURBOC__
buffer = MK_FP(theseg, 0);
#endif
bufptr = buffer;
while ((ret = read(fdin, copybuffer, COPY_SIZE)) > 0)
{
UWORD offs;
if ((copied+ret) > *filesize)
{
ULONG dropped = copied + ret - *filesize;
printf("More bytes received than expected, dropping %lu??", dropped);
ret = ret - (UWORD) dropped;
}
for (offs = 0; offs < ret; offs++)
{
*bufptr = copybuffer[offs];
bufptr++;
if (FP_OFF(bufptr) > 0x7777) /* watcom needs this in tiny model */
{
bufptr = MK_FP(FP_SEG(bufptr)+0x700, FP_OFF(bufptr)-0x7000);
}
}
copied += ret;
}
} /* reading */
if (!reading) /* writing */
{
BYTE far * bufptr = buffer;
while (TRUE)
{
UWORD offs;
ULONG tocopy = *filesize - copied;
if (tocopy==0)
break; /* done */
if (tocopy > (ULONG)COPY_SIZE)
tocopy = COPY_SIZE; /* cannot do all in one go */
for (offs=0; offs < tocopy; offs++)
{
copybuffer[offs] = *bufptr;
bufptr++;
if (FP_OFF(bufptr) > 0x7777) /* watcom needs this in tiny model */
{
bufptr = MK_FP(FP_SEG(bufptr)+0x700, FP_OFF(bufptr)-0x7000);
}
}
ret = (UWORD) tocopy;
if (write(fdout, copybuffer, ret) != ret)
{
printf("Can't write %u bytes to %s\n", ret, dest);
close(fdout);
unlink(dest);
break;
}
copied += ret;
}
} /* writing */
#if 0 /* TODO: Clone file timestamps even in 2 pass copy mode... */
{ {
#if defined __WATCOMC__ || defined _MSC_VER /* || defined __BORLANDC__ */ #if defined __WATCOMC__ || defined _MSC_VER /* || defined __BORLANDC__ */
unsigned short date, time; unsigned short date, time;
@ -1017,10 +1173,14 @@ BOOL copy(COUNT drive, BYTE * srcPath, BYTE * rootPath, BYTE * file)
setftime(fdout, &ftime); setftime(fdout, &ftime);
#endif #endif
} }
#endif /* timestamps */
close(fdin); if (reading)
close(fdout); close(fdin);
if (!reading)
close(fdout);
#if 0 /* no way :-p */
#ifdef __SOME_OTHER_COMPILER__ #ifdef __SOME_OTHER_COMPILER__
{ {
#include <utime.h> #include <utime.h>
@ -1030,10 +1190,11 @@ BOOL copy(COUNT drive, BYTE * srcPath, BYTE * rootPath, BYTE * file)
utimb.modtime = fstatbuf.st_mtime; /* modification time */ utimb.modtime = fstatbuf.st_mtime; /* modification time */
utime(dest, &utimb); utime(dest, &utimb);
}; };
#endif
#endif #endif
printf("%lu Bytes transferred", copied); printf("%lu Bytes transferred", copied);
return TRUE; return buffer;
} /* copy */ } /* copy */