Build: Use share submodule
1/ Replace copy of share with submodule 2/ Add to the CI build
This commit is contained in:
parent
23d9c2ecf0
commit
778a03f8c3
7
.github/workflows/ci-build.yml
vendored
7
.github/workflows/ci-build.yml
vendored
@ -16,13 +16,16 @@ jobs:
|
||||
runs-on: ubuntu-20.04
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Checkout repository and submodules
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Package install
|
||||
run: |
|
||||
sudo add-apt-repository ppa:tkchia/build-ia16
|
||||
sudo apt update
|
||||
sudo apt install gcc-ia16-elf nasm upx
|
||||
sudo apt install gcc-ia16-elf libi86-ia16-elf nasm upx
|
||||
|
||||
- name: build
|
||||
run: ./ci_build.sh
|
||||
|
4
.gitmodules
vendored
Normal file
4
.gitmodules
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
[submodule "share"]
|
||||
path = share
|
||||
url = https://github.com/FDOS/share.git
|
||||
ignore = untracked
|
@ -14,7 +14,11 @@ mkdir _output
|
||||
# GCC
|
||||
git clean -x -d -f -e _output -e _watcom -e ow-snapshot.tar.gz
|
||||
make all COMPILER=gcc
|
||||
mv -i bin/KGC*.map bin/KGC*.sys _output/.
|
||||
mv -n bin/KGC*.map bin/KGC*.sys _output/.
|
||||
# GCC share
|
||||
(cd share && make clobber && env COMPILER=gcc ./build.sh)
|
||||
mv -n share/share.com _output/gshare.com
|
||||
mv -n share/share.map _output/gshare.map
|
||||
|
||||
# Watcom
|
||||
if [ ! -d _watcom ] ; then
|
||||
@ -29,6 +33,6 @@ export WATCOM=$TRAVIS_BUILD_DIR/_watcom
|
||||
|
||||
git clean -x -d -f -e _output -e _watcom -e ow-snapshot.tar.gz
|
||||
make all COMPILER=owlinux
|
||||
mv -i bin/KWC*.map bin/KWC*.sys _output/.
|
||||
mv -n bin/KWC*.map bin/KWC*.sys _output/.
|
||||
|
||||
echo done
|
||||
|
1
share
Submodule
1
share
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 3041309c0ff952fa0a778bd86704488328f2f342
|
@ -1,42 +0,0 @@
|
||||
|
||||
# nmake makefile
|
||||
# share must be linked as COM file
|
||||
# best is to use TC 2.01 which is freely available
|
||||
|
||||
USETC2=1
|
||||
COM=1
|
||||
|
||||
!if $(USETC2)
|
||||
CCBASE=c:\tc201
|
||||
BINBASE=
|
||||
!else
|
||||
CCBASE=c:\tc30
|
||||
BINBASE=\bin
|
||||
!endif
|
||||
|
||||
!if $(COM)
|
||||
COPT=-c -mt -1 -I$(INCLUDE)
|
||||
LOPT=/m /s /c /t
|
||||
!else
|
||||
COPT=-c -ms -1 -I$(INCLUDE)
|
||||
LOPT=/m /s /c
|
||||
!endif
|
||||
|
||||
CC=$(CCBASE)$(BINBASE)\tcc
|
||||
LD=$(CCBASE)$(BINBASE)\tlink
|
||||
LIBS=$(CCBASE)\lib
|
||||
INCLUDE=$(CCBASE)\include
|
||||
|
||||
SHARE.COM: SHARE.OBJ
|
||||
$(LD) $(LOPT) $(LIBS)\c0t.obj share.obj,share.com,,$(LIBS)\cs.lib
|
||||
|
||||
SHARE.OBJ: SHARE.C
|
||||
$(CC) $(COPT) share.c
|
||||
|
||||
CLEAN:
|
||||
del *.obj
|
||||
|
||||
CLOBBER: CLEAN
|
||||
del *.com
|
||||
del *.exe
|
||||
del *.map
|
761
share/share.c
761
share/share.c
@ -1,761 +0,0 @@
|
||||
/*
|
||||
FreeDOS SHARE
|
||||
Copyright (c) 2000 Ronald B. Cemer under the GNU GPL
|
||||
You know the drill.
|
||||
If not, see www.gnu.org for details. Read it, learn it, BE IT. :-)
|
||||
*/
|
||||
|
||||
/* #include <stdio.h> */ /* (fprintf removed...) */
|
||||
/* #include <fcntl.h> */ /* Not used, using defines below... */
|
||||
#include <io.h> /* write (what else?) */
|
||||
#include <stdlib.h> /* _psp, NULL, malloc, free, atol, atoi */
|
||||
#include <dos.h> /* MK_FP, FP_OFF, FP_SEG, int86, intdosx, */
|
||||
/* freemem, keep */
|
||||
#include <string.h> /* strchr, strlen, memset */
|
||||
|
||||
#ifndef __TURBOC__
|
||||
#error "This software must be compiled with TurboC or TurboC++."
|
||||
#endif
|
||||
|
||||
/* Changed by Eric Auer 5/2004: Squeezing executable size a bit -> */
|
||||
/* Replaced fprint(stderr or stdout,...) by write(hand, buf, size) */
|
||||
/* Keeps stream stuff and printf stuff outside the file and TSR... */
|
||||
|
||||
/* ------------- DEFINES ------------- */
|
||||
#define MUX_INT_NO 0x2f
|
||||
#define MULTIPLEX_ID 0x10
|
||||
|
||||
#define FILE_TABLE_MIN 128
|
||||
#define FILE_TABLE_MAX 62000U
|
||||
|
||||
#define LOCK_TABLE_MIN 1
|
||||
#define LOCK_TABLE_MAX 3800
|
||||
|
||||
/* Valid values for openmode: */
|
||||
#define OPEN_READ_ONLY 0
|
||||
#define OPEN_WRITE_ONLY 1
|
||||
#define OPEN_READ_WRITE 2
|
||||
|
||||
/* Valid values for sharemode: */
|
||||
#define SHARE_COMPAT 0
|
||||
#define SHARE_DENY_ALL 1
|
||||
#define SHARE_DENY_WRITE 2
|
||||
#define SHARE_DENY_READ 3
|
||||
#define SHARE_DENY_NONE 4
|
||||
|
||||
/* ------------- TYPEDEFS ------------- */
|
||||
/* Register structure for an interrupt function. */
|
||||
typedef struct {
|
||||
unsigned bp;
|
||||
unsigned di;
|
||||
unsigned si;
|
||||
unsigned ds;
|
||||
unsigned es;
|
||||
unsigned dx;
|
||||
unsigned cx;
|
||||
unsigned bx;
|
||||
unsigned ax;
|
||||
unsigned ip;
|
||||
unsigned cs;
|
||||
unsigned flags;
|
||||
} intregs_t;
|
||||
|
||||
/* This table determines the action to take when attempting to open
|
||||
a file. The first array index is the sharing mode of a previous
|
||||
open on the same file. The second array index is the sharing mode
|
||||
of the current open attempt on the same file. Action codes are
|
||||
defined as follows:
|
||||
0 = open may proceed
|
||||
1 = open fails with error code 05h
|
||||
2 = open fails and an INT 24h is generated
|
||||
3 = open proceeds if the file is read-only; otherwise fails
|
||||
with error code (used only in exception table below)
|
||||
4 = open proceeds if the file is read-only; otherwise fails
|
||||
with INT 24H (used only in exception table below)
|
||||
Exceptions to the rules are handled in the table
|
||||
below, so this table only covers the general rules.
|
||||
*/
|
||||
static unsigned char open_actions[5][5] = {
|
||||
{ 0, 1, 1, 1, 1 },
|
||||
{ 2, 1, 1, 1, 1 },
|
||||
{ 2, 1, 1, 1, 1 },
|
||||
{ 2, 1, 1, 1, 1 },
|
||||
{ 2, 1, 1, 1, 0 },
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
unsigned char first_sharemode;
|
||||
unsigned char first_openmode;
|
||||
unsigned char current_sharemode;
|
||||
unsigned char current_openmode;
|
||||
unsigned char action;
|
||||
} open_action_exception_t;
|
||||
|
||||
static open_action_exception_t open_exceptions[] = {
|
||||
{ 0, 0, 2, 0, 3 },
|
||||
{ 0, 0, 4, 0, 3 }, /* compatibility-read/deny none-read, MED 08/2004 */
|
||||
{ 2, 0, 0, 0, 4 },
|
||||
{ 2, 0, 2, 0, 0 },
|
||||
{ 2, 0, 4, 0, 0 },
|
||||
{ 3, 0, 2, 1, 0 },
|
||||
{ 3, 0, 4, 1, 0 },
|
||||
{ 3, 1, 4, 1, 0 },
|
||||
{ 3, 2, 4, 1, 0 },
|
||||
{ 4, 0, 0, 0, 4 },
|
||||
{ 4, 0, 0, 1, 0 }, /* deny none-read/compatibility-write */
|
||||
{ 4, 0, 0, 2, 0 }, /* deny none-read/compatibility-read+write */
|
||||
{ 4, 0, 2, 0, 0 },
|
||||
{ 4, 0, 2, 1, 0 },
|
||||
{ 4, 0, 2, 2, 0 },
|
||||
{ 4, 1, 3, 0, 0 },
|
||||
{ 4, 1, 3, 1, 0 },
|
||||
{ 4, 1, 3, 2, 0 },
|
||||
};
|
||||
|
||||
/* One of these exists for each instance of an open file. */
|
||||
typedef struct {
|
||||
char filename[128]; /* fully-qualified filename; "\0" if unused */
|
||||
unsigned short psp; /* PSP of process which opened this file */
|
||||
unsigned char openmode; /* 0=read-only, 1=write-only, 2=read-write */
|
||||
unsigned char sharemode;/* SHARE_COMPAT, etc... */
|
||||
unsigned char first_openmode; /* openmode of first open */
|
||||
unsigned char first_sharemode; /* sharemode of first open */
|
||||
} file_t;
|
||||
|
||||
/* One of these exists for each active lock region. */
|
||||
typedef struct {
|
||||
unsigned char used; /* Non-zero if this entry is used. */
|
||||
unsigned long start; /* Beginning offset of locked region */
|
||||
unsigned long end; /* Ending offset of locked region */
|
||||
unsigned short fileno; /* file_table entry number */
|
||||
unsigned short psp; /* PSP of process which owns the lock */
|
||||
} lock_t;
|
||||
|
||||
|
||||
/* ------------- GLOBALS ------------- */
|
||||
static char progname[9];
|
||||
static unsigned int file_table_size_bytes = 2048;
|
||||
static unsigned int file_table_size = 0; /* # of file_t we can have */
|
||||
static file_t *file_table = NULL;
|
||||
static unsigned int lock_table_size = 20; /* # of lock_t we can have */
|
||||
static lock_t *lock_table = NULL;
|
||||
|
||||
|
||||
/* ------------- PROTOTYPES ------------- */
|
||||
/* PRINT added by Eric */
|
||||
#define ERR 2 /* handle of stderr */
|
||||
#define OUT 1 /* handle of stdout */
|
||||
static void PRINT(int handle, char * text);
|
||||
static void PRINT(int handle, char * text) {
|
||||
(void)write (handle, text, strlen(text));
|
||||
/* return value is -1 error or N bytes_written. Ignored. */
|
||||
};
|
||||
|
||||
|
||||
/* DOS calls this to see if it's okay to open the file.
|
||||
Returns a file_table entry number to use (>= 0) if okay
|
||||
to open. Otherwise returns < 0 and may generate a critical
|
||||
error. If < 0 is returned, it is the negated error return
|
||||
code, so DOS simply negates this value and returns it in
|
||||
AX. */
|
||||
static int open_check
|
||||
(char far *filename,/* far pointer to fully qualified filename */
|
||||
unsigned short psp,/* psp segment address of owner process */
|
||||
int openmode, /* 0=read-only, 1=write-only, 2=read-write */
|
||||
int sharemode); /* SHARE_COMPAT, etc... */
|
||||
|
||||
/* DOS calls this to record the fact that it has successfully
|
||||
closed a file, or the fact that the open for this file failed. */
|
||||
static void close_file
|
||||
(int fileno); /* file_table entry number */
|
||||
|
||||
/* DOS calls this to determine whether it can access (read or
|
||||
write) a specific section of a file. We call it internally
|
||||
from lock_unlock (only when locking) to see if any portion
|
||||
of the requested region is already locked. If psp is zero,
|
||||
then it matches any psp in the lock table. Otherwise, only
|
||||
locks which DO NOT belong to psp will be considered.
|
||||
Returns zero if okay to access or lock (no portion of the
|
||||
region is already locked). Otherwise returns non-zero and
|
||||
generates a critical error (if allowcriter is non-zero).
|
||||
If non-zero is returned, it is the negated return value for
|
||||
the DOS call. */
|
||||
static int access_check
|
||||
(unsigned short psp,/* psp segment address of owner process */
|
||||
int fileno, /* file_table entry number */
|
||||
unsigned long ofs, /* offset into file */
|
||||
unsigned long len, /* length (in bytes) of region to access */
|
||||
int allowcriter); /* allow a critical error to be generated */
|
||||
|
||||
/* DOS calls this to lock or unlock a specific section of a file.
|
||||
Returns zero if successfully locked or unlocked. Otherwise
|
||||
returns non-zero.
|
||||
If the return value is non-zero, it is the negated error
|
||||
return code for the DOS 0x5c call. */
|
||||
static int lock_unlock
|
||||
(unsigned short psp,/* psp segment address of owner process */
|
||||
int fileno, /* file_table entry number */
|
||||
unsigned long ofs, /* offset into file */
|
||||
unsigned long len, /* length (in bytes) of region to lock or unlock */
|
||||
int unlock); /* non-zero to unlock; zero to lock */
|
||||
|
||||
/* Multiplex interrupt handler */
|
||||
|
||||
static void interrupt far (*old_handler2f)() = NULL;
|
||||
|
||||
|
||||
/* ------------- HOOK ------------- */
|
||||
static void interrupt far handler2f(intregs_t iregs) {
|
||||
|
||||
#define chain_old_handler2f { \
|
||||
_BX = iregs.bx; /* Restore BX */ \
|
||||
_CX = iregs.ax; /* Save original AX contents into CX */ \
|
||||
iregs.ax = FP_SEG((void far *)old_handler2f); /* Set chain segment */ \
|
||||
iregs.bx = FP_OFF((void far *)old_handler2f); /* Set chain offset */ \
|
||||
_AX = _CX; /* Restore AX */ \
|
||||
__emit__(0x5D); /* POP BP */ \
|
||||
__emit__(0x5F); /* POP DI */ \
|
||||
__emit__(0x5E); /* POP SI */ \
|
||||
__emit__(0x1F); /* POP DS */ \
|
||||
__emit__(0x07); /* POP ES */ \
|
||||
__emit__(0x5A); /* POP DX */ \
|
||||
__emit__(0x59); /* POP CX */ \
|
||||
__emit__(0xCB); /* RETF */ \
|
||||
} /* This evil trick probably only works with Turbo C!?! */
|
||||
/* would have been better to link a NASM handler core: */
|
||||
/* nasm -fobj -o foo.obj foo.asm ... */
|
||||
|
||||
if (((iregs.ax >> 8) & 0xff) == MULTIPLEX_ID) {
|
||||
if ((iregs.ax & 0xff) == 0) {
|
||||
/* Installation check. Return 0xff in AL. */
|
||||
iregs.ax |= 0xff;
|
||||
return;
|
||||
}
|
||||
/* These subfuctions are nonstandard, but are highly
|
||||
unlikely to be used by another multiplex TSR, since
|
||||
our multiplex Id (0x10) is basically reserved for
|
||||
SHARE. So we should be able to get away with using
|
||||
these for our own purposes. */
|
||||
/* open_check */
|
||||
if ((iregs.ax & 0xff) == 0xa0) {
|
||||
iregs.ax = open_check
|
||||
(MK_FP(iregs.ds, iregs.si),
|
||||
iregs.bx,
|
||||
iregs.cx,
|
||||
iregs.dx);
|
||||
return;
|
||||
}
|
||||
/* close_file */
|
||||
if ((iregs.ax & 0xff) == 0xa1) {
|
||||
close_file(iregs.bx);
|
||||
return;
|
||||
}
|
||||
/* access_check (0xa2) */
|
||||
/* access_check with critical error (0xa3) */
|
||||
if ((iregs.ax & 0xfe) == 0xa2) {
|
||||
iregs.ax = access_check
|
||||
(iregs.bx,
|
||||
iregs.cx,
|
||||
#if 0
|
||||
( ((((unsigned long)iregs.si)<<16) & 0xffff0000L) |
|
||||
(((unsigned long)iregs.di) & 0xffffL) ),
|
||||
( ((((unsigned long)iregs.es)<<16) & 0xffff0000L) |
|
||||
(((unsigned long)iregs.dx) & 0xffffL) ),
|
||||
#else
|
||||
( (((unsigned long)iregs.si)<<16) + iregs.di ),
|
||||
( (((unsigned long)iregs.es)<<16) + iregs.dx ),
|
||||
#endif
|
||||
(iregs.ax & 0x01));
|
||||
return;
|
||||
}
|
||||
/* lock_unlock lock (0xa4)*/
|
||||
/* lock_unlock unlock (0xa5) */
|
||||
if ((iregs.ax & 0xfe) == 0xa4) {
|
||||
iregs.ax = lock_unlock
|
||||
(iregs.bx,
|
||||
iregs.cx,
|
||||
#if 0
|
||||
( ((((unsigned long)iregs.si)<<16) & 0xffff0000L) |
|
||||
(((unsigned long)iregs.di) & 0xffffL) ),
|
||||
( ((((unsigned long)iregs.es)<<16) & 0xffff0000L) |
|
||||
(((unsigned long)iregs.dx) & 0xffffL) ),
|
||||
#else
|
||||
( (((unsigned long)iregs.si)<<16) | ((unsigned long)iregs.di) ),
|
||||
( (((unsigned long)iregs.es)<<16) | ((unsigned long)iregs.dx) ),
|
||||
#endif
|
||||
(iregs.ax & 0x01));
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* Chain to the next handler. */
|
||||
chain_old_handler2f;
|
||||
}
|
||||
|
||||
static void remove_all_locks(int fileno) {
|
||||
int i;
|
||||
lock_t *lptr;
|
||||
|
||||
for (i = 0; i < lock_table_size; i++) {
|
||||
lptr = &lock_table[i];
|
||||
if (lptr->fileno == fileno) lptr->used = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void free_file_table_entry(int fileno) {
|
||||
file_table[fileno].filename[0] = '\0';
|
||||
}
|
||||
|
||||
/* DOS 7 does not have read-only restrictions, MED 08/2004 */
|
||||
/*
|
||||
static int file_is_read_only(char far *filename) {
|
||||
union REGS regs;
|
||||
struct SREGS sregs;
|
||||
|
||||
regs.x.ax = 0x4300;
|
||||
sregs.ds = FP_SEG(filename);
|
||||
regs.x.dx = FP_OFF(filename);
|
||||
intdosx(®s, ®s, &sregs);
|
||||
if (regs.x.cflag) return 0;
|
||||
return ((regs.h.cl & 0x19) == 0x01);
|
||||
}
|
||||
*/
|
||||
|
||||
static int fnmatches(char far *fn1, char far *fn2) {
|
||||
while (*fn1) {
|
||||
if (*fn1 != *fn2) return 0;
|
||||
fn1++;
|
||||
fn2++;
|
||||
}
|
||||
return (*fn1 == *fn2);
|
||||
}
|
||||
|
||||
static int do_open_check
|
||||
(int fileno) { /* file_table entry number */
|
||||
file_t *p, *fptr = &file_table[fileno];
|
||||
int i, j, action = 0, foundexc;
|
||||
unsigned char current_sharemode = fptr->sharemode;
|
||||
unsigned char current_openmode = fptr->openmode;
|
||||
open_action_exception_t *excptr;
|
||||
|
||||
fptr->first_sharemode = fptr->sharemode;
|
||||
fptr->first_openmode = fptr->openmode;
|
||||
for (i = 0; i < file_table_size; i++) {
|
||||
if (i == fileno) continue;
|
||||
p = &file_table[i];
|
||||
if (p->filename[0] == '\0') continue;
|
||||
if (!fnmatches(p->filename, fptr->filename)) continue;
|
||||
fptr->first_sharemode = p->first_sharemode;
|
||||
fptr->first_openmode = p->first_openmode;
|
||||
/* Look for exceptions to the general rules first. */
|
||||
foundexc = 0;
|
||||
for (j = 0;
|
||||
j < (sizeof(open_exceptions)/sizeof(open_action_exception_t));
|
||||
j++) {
|
||||
excptr = &open_exceptions[j];
|
||||
if ( (excptr->first_sharemode == fptr->first_sharemode)
|
||||
&& (excptr->current_sharemode == current_sharemode)
|
||||
&& (excptr->first_openmode == fptr->first_openmode)
|
||||
&& (excptr->current_openmode == current_openmode) ) {
|
||||
foundexc = 1;
|
||||
action = excptr->action;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* If no exception to rules, use normal rules. */
|
||||
if (!foundexc)
|
||||
action = open_actions[fptr->first_sharemode][current_sharemode];
|
||||
/* Fail appropriately based on action. */
|
||||
switch (action) {
|
||||
|
||||
/* DOS 7 does not have read-only restrictions, fall through to proceed, MED 08/2004 */
|
||||
case 3:
|
||||
case 4:
|
||||
|
||||
case 0: /* proceed with open */
|
||||
break;
|
||||
/* case 3: */ /* succeed if file read-only, else fail with error 05h */
|
||||
/* if (file_is_read_only(fptr->filename)) break; */
|
||||
case 1: /* fail with error code 05h */
|
||||
free_file_table_entry(fileno);
|
||||
return -5;
|
||||
/* case 4: */ /* succeed if file read-only, else fail with int 24h */
|
||||
/* if (file_is_read_only(fptr->filename)) break; */
|
||||
case 2: /* fail with int 24h */
|
||||
{
|
||||
union REGS regs;
|
||||
|
||||
regs.h.ah = 0x0e; /* disk I/O; fail allowed; data area */
|
||||
regs.h.al = 0;
|
||||
regs.x.di = 0x0d; /* sharing violation */
|
||||
if ( (fptr->filename[0]!='\0') && (fptr->filename[1]==':') )
|
||||
regs.h.al = fptr->filename[0]-'A';
|
||||
free_file_table_entry(fileno);
|
||||
int86(0x24, ®s, ®s);
|
||||
}
|
||||
return -0x20; /* sharing violation */
|
||||
}
|
||||
break;
|
||||
}
|
||||
return fileno;
|
||||
}
|
||||
|
||||
/* DOS calls this to see if it's okay to open the file.
|
||||
Returns a file_table entry number to use (>= 0) if okay
|
||||
to open. Otherwise returns < 0 and may generate a critical
|
||||
error. If < 0 is returned, it is the negated error return
|
||||
code, so DOS simply negates this value and returns it in
|
||||
AX. */
|
||||
static int open_check
|
||||
(char far *filename,/* far pointer to fully qualified filename */
|
||||
unsigned short psp,/* psp segment address of owner process */
|
||||
int openmode, /* 0=read-only, 1=write-only, 2=read-write */
|
||||
int sharemode) { /* SHARE_COMPAT, etc... */
|
||||
|
||||
int i, fileno = -1;
|
||||
file_t *fptr;
|
||||
|
||||
/* Whack off unused bits in the share mode
|
||||
in case we were careless elsewhere. */
|
||||
sharemode &= 0x07;
|
||||
|
||||
/* Assume compatibility mode if invalid share mode. */
|
||||
/* ??? IS THIS CORRECT ??? */
|
||||
if ( (sharemode < SHARE_COMPAT) || (sharemode > SHARE_DENY_NONE) )
|
||||
sharemode = SHARE_COMPAT;
|
||||
|
||||
/* Whack off unused bits in the open mode
|
||||
in case we were careless elsewhere. */
|
||||
openmode &= 0x03;
|
||||
|
||||
/* Assume read-only mode if invalid open mode. */
|
||||
/* ??? IS THIS CORRECT ??? */
|
||||
if ( (openmode < OPEN_READ_ONLY) || (openmode > OPEN_READ_WRITE) )
|
||||
openmode = OPEN_READ_ONLY;
|
||||
|
||||
for (i = 0; i < file_table_size; i++) {
|
||||
if (file_table[i].filename[0] == '\0') {
|
||||
fileno = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (fileno == -1) return -1;
|
||||
fptr = &file_table[fileno];
|
||||
|
||||
/* Copy the filename into ftpr->filename. */
|
||||
for (i = 0; i < sizeof(fptr->filename); i++) {
|
||||
if ((fptr->filename[i] = filename[i]) == '\0') break;
|
||||
}
|
||||
fptr->psp = psp;
|
||||
fptr->openmode = (unsigned char)openmode;
|
||||
fptr->sharemode = (unsigned char)sharemode;
|
||||
/* Do the sharing check and return fileno if
|
||||
okay, or < 0 (and free the entry) if error. */
|
||||
return do_open_check(fileno);
|
||||
}
|
||||
|
||||
/* DOS calls this to record the fact that it has successfully
|
||||
closed a file, or the fact that the open for this file failed. */
|
||||
static void close_file
|
||||
(int fileno) { /* file_table entry number */
|
||||
|
||||
remove_all_locks(fileno);
|
||||
free_file_table_entry(fileno);
|
||||
}
|
||||
|
||||
/* DOS calls this to determine whether it can access (read or
|
||||
write) a specific section of a file. We call it internally
|
||||
from lock_unlock (only when locking) to see if any portion
|
||||
of the requested region is already locked. If psp is zero,
|
||||
then it matches any psp in the lock table. Otherwise, only
|
||||
locks which DO NOT belong to psp will be considered.
|
||||
Returns zero if okay to access or lock (no portion of the
|
||||
region is already locked). Otherwise returns non-zero and
|
||||
generates a critical error (if allowcriter is non-zero).
|
||||
If non-zero is returned, it is the negated return value for
|
||||
the DOS call. */
|
||||
static int access_check
|
||||
(unsigned short psp,/* psp segment address of owner process */
|
||||
int fileno, /* file_table entry number */
|
||||
unsigned long ofs, /* offset into file */
|
||||
unsigned long len, /* length (in bytes) of region to access */
|
||||
int allowcriter) { /* allow a critical error to be generated */
|
||||
int i;
|
||||
file_t *fptr = &file_table[fileno];
|
||||
char far *filename = fptr->filename;
|
||||
lock_t *lptr;
|
||||
unsigned long endofs = ofs + len;
|
||||
|
||||
if (endofs < ofs) {
|
||||
endofs = 0xffffffffL;
|
||||
len = endofs-ofs;
|
||||
}
|
||||
|
||||
if (len < 1L) return 0;
|
||||
|
||||
for (i = 0; i < lock_table_size; i++) {
|
||||
lptr = &lock_table[i];
|
||||
if ( (lptr->used)
|
||||
&& ( (psp == 0) || (lptr->psp != psp) )
|
||||
&& (fnmatches(filename, file_table[lptr->fileno].filename))
|
||||
&& ( ( (ofs>=lptr->start) && (ofs<lptr->end) )
|
||||
|| ( (endofs>lptr->start) && (endofs<=lptr->end) ) ) ) {
|
||||
if (allowcriter) {
|
||||
union REGS regs;
|
||||
|
||||
regs.h.ah = 0x0e; /* disk I/O; fail allowed; data area */
|
||||
regs.h.al = 0;
|
||||
regs.x.di = 0x0e; /* lock violation */
|
||||
if ( (fptr->filename[0]!='\0') && (fptr->filename[1]==':') )
|
||||
regs.h.al = fptr->filename[0]-'A';
|
||||
free_file_table_entry(fileno);
|
||||
int86(0x24, ®s, ®s);
|
||||
}
|
||||
return -0x21; /* lock violation */
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* DOS calls this to lock or unlock a specific section of a file.
|
||||
Returns zero if successfully locked or unlocked. Otherwise
|
||||
returns non-zero.
|
||||
If the return value is non-zero, it is the negated error
|
||||
return code for the DOS 0x5c call. */
|
||||
static int lock_unlock
|
||||
(unsigned short psp,/* psp segment address of owner process */
|
||||
int fileno, /* file_table entry number */
|
||||
unsigned long ofs, /* offset into file */
|
||||
unsigned long len, /* length (in bytes) of region to lock or unlock */
|
||||
int unlock) { /* non-zero to unlock; zero to lock */
|
||||
|
||||
int i;
|
||||
lock_t *lptr;
|
||||
unsigned long endofs = ofs + len;
|
||||
|
||||
if (endofs < ofs) {
|
||||
endofs = 0xffffffffL;
|
||||
len = endofs-ofs;
|
||||
}
|
||||
|
||||
if (len < 1L) return 0;
|
||||
|
||||
/* there was a error in the code below preventing any other
|
||||
than the first locked region to be unlocked (japheth, 09/2005) */
|
||||
|
||||
if (unlock) {
|
||||
for (i = 0; i < lock_table_size; i++) {
|
||||
lptr = &lock_table[i];
|
||||
if ( (lptr->used)
|
||||
&& (lptr->psp == psp)
|
||||
&& (lptr->fileno == fileno)
|
||||
&& (lptr->start == ofs)
|
||||
&& (lptr->end == endofs) ) {
|
||||
lptr->used = 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* Not already locked by us; can't unlock. */
|
||||
return -(0x21); /* lock violation */
|
||||
} else {
|
||||
if (access_check(0, fileno, ofs, len, 0)) {
|
||||
/* Already locked; can't lock. */
|
||||
return -(0x21); /* lock violation */
|
||||
}
|
||||
for (i = 0; i < lock_table_size; i++) {
|
||||
lptr = &lock_table[i];
|
||||
if (!lptr->used) {
|
||||
lptr->used = 1;
|
||||
lptr->start = ofs;
|
||||
lptr->end = ofs+(unsigned long)len;
|
||||
lptr->fileno = fileno;
|
||||
lptr->psp = psp;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -(0x24); /* sharing buffer overflow */
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------- INIT ------------- */
|
||||
/* Allocate tables and install hooks into the kernel.
|
||||
If we run out of memory, return non-zero. */
|
||||
static int init(void) {
|
||||
/* int i; */
|
||||
|
||||
file_table_size = file_table_size_bytes/sizeof(file_t);
|
||||
if ((file_table=malloc(file_table_size_bytes)) == NULL)
|
||||
return 1;
|
||||
memset(file_table, 0, file_table_size_bytes);
|
||||
if ((lock_table=malloc(lock_table_size*sizeof(lock_t))) == NULL)
|
||||
return 1;
|
||||
memset(lock_table, 0, lock_table_size*sizeof(lock_t));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void usage(void) {
|
||||
PRINT(ERR,
|
||||
"Installs file-sharing and locking "
|
||||
"capabilities on your hard disk.\r\n\r\n");
|
||||
PRINT(ERR, progname);
|
||||
PRINT(ERR, " [/F:space] [/L:locks]\r\n\r\n"
|
||||
" /F:space Allocates file space (in bytes) "
|
||||
"for file-sharing information.\r\n"
|
||||
" /L:locks Sets the number of files that can "
|
||||
"be locked at one time.\r\n");
|
||||
}
|
||||
|
||||
static void bad_params(void) {
|
||||
PRINT(ERR, progname);
|
||||
PRINT(ERR, ": parameter out of range!\r\n");
|
||||
}
|
||||
|
||||
static void out_of_memory(void) {
|
||||
PRINT(ERR, progname);
|
||||
PRINT(ERR,": out of memory!\r\n");
|
||||
}
|
||||
|
||||
/* ------------- MAIN ------------- */
|
||||
int main(int argc, char **argv) {
|
||||
unsigned short far *usfptr;
|
||||
unsigned char far *uscptr;
|
||||
unsigned short top_of_tsr;
|
||||
int installed = 0;
|
||||
int i;
|
||||
|
||||
/* Extract program name from argv[0] into progname. */
|
||||
if (argv[0] != NULL) {
|
||||
char *p = argv[0], *p2, c;
|
||||
int i;
|
||||
if ( (p[0] != '\0') && (p[1] == ':') )
|
||||
p += 2;
|
||||
while ((p2 = strchr(p, '\\')) != NULL)
|
||||
p = p2+1;
|
||||
p2 = progname;
|
||||
for (i = 0; i < 8; i++) {
|
||||
c = p[i];
|
||||
if ( (c == '.') || (c == '\0') )
|
||||
break;
|
||||
*(p2++) = c;
|
||||
}
|
||||
*p2 = '\0';
|
||||
}
|
||||
|
||||
/* See if the TSR is already installed. */
|
||||
/* disable(); */ /* no multitasking, so don't worry */
|
||||
if (getvect(MUX_INT_NO) != NULL) {
|
||||
union REGS regs;
|
||||
/* enable(); */
|
||||
regs.h.ah = MULTIPLEX_ID;
|
||||
regs.h.al = 0;
|
||||
int86(MUX_INT_NO,®s,®s);
|
||||
installed = ((regs.x.ax & 0xff) == 0xff);
|
||||
|
||||
} /* else { enable(); } */
|
||||
|
||||
/* Process command line arguments. Bail if errors. */
|
||||
for (i = 1; i < argc; i++) {
|
||||
char *arg = argv[i];
|
||||
if (arg == NULL) continue;
|
||||
if (arg[0] != '/') {
|
||||
usage();
|
||||
return 3;
|
||||
}
|
||||
arg++;
|
||||
switch(*arg) {
|
||||
case '?':
|
||||
usage();
|
||||
return 3;
|
||||
case 'f':
|
||||
case 'F':
|
||||
arg++;
|
||||
if (*arg != ':') {
|
||||
usage();
|
||||
return 3;
|
||||
}
|
||||
arg++;
|
||||
{
|
||||
long temp = atol(arg);
|
||||
if ( (temp < (long)FILE_TABLE_MIN)
|
||||
|| (temp > (long)FILE_TABLE_MAX) ) {
|
||||
bad_params();
|
||||
return 3;
|
||||
}
|
||||
file_table_size_bytes = (unsigned int)temp;
|
||||
}
|
||||
break;
|
||||
case 'l':
|
||||
case 'L':
|
||||
arg++;
|
||||
if (*arg != ':') {
|
||||
usage();
|
||||
return 3;
|
||||
}
|
||||
arg++;
|
||||
lock_table_size = atoi(arg);
|
||||
if ( (lock_table_size < LOCK_TABLE_MIN)
|
||||
|| (lock_table_size > LOCK_TABLE_MAX) ) {
|
||||
bad_params();
|
||||
return 3;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now try to install. */
|
||||
|
||||
if (installed) {
|
||||
PRINT(ERR, progname);
|
||||
PRINT(ERR, " is already installed!\r\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (init() != 0) {
|
||||
out_of_memory();
|
||||
return 2;
|
||||
}
|
||||
|
||||
/* Allocate a single byte. This tells us the size of the TSR.
|
||||
Free the byte when we know the address. */
|
||||
uscptr = (unsigned char far *)malloc(1);
|
||||
if (uscptr == NULL) {
|
||||
out_of_memory();
|
||||
return 2;
|
||||
}
|
||||
top_of_tsr = (FP_SEG(uscptr)+((FP_OFF(uscptr)+15) >> 4)) - _psp;
|
||||
/* resident paras, counting from PSP:0 */
|
||||
free((void *)uscptr);
|
||||
|
||||
|
||||
/* Hook the interrupt for the handler routine. */
|
||||
/* disable(); */
|
||||
old_handler2f = getvect(MUX_INT_NO);
|
||||
setvect(MUX_INT_NO,handler2f);
|
||||
/* enable(); */
|
||||
|
||||
/* Let them know we're installed. */
|
||||
PRINT(OUT, progname);
|
||||
PRINT(OUT, " installed.\r\n");
|
||||
|
||||
/* Any access to environment variables must */
|
||||
/* be done prior to this point. Here we */
|
||||
/* free the environment table to prevent */
|
||||
/* wasting that memory. In fact, if the */
|
||||
/* TSR were removed from memory and we did */
|
||||
/* not do this, we would not be able to */
|
||||
/* recover this memory. */
|
||||
|
||||
usfptr = MK_FP(_psp, 0x2c); /* MK_FP is the counterpart */
|
||||
/* of FP_OFF and FP_SEG ... */
|
||||
freemem(*usfptr); /* deallocate MCB of ENV segment */
|
||||
|
||||
#if 0
|
||||
/* Free the remainder of memory for use by applications. */
|
||||
setblock(_psp,top_of_tsr);
|
||||
/* resize self: already done by keep() */
|
||||
#endif
|
||||
|
||||
/* Terminate and stay resident. */
|
||||
keep(0,top_of_tsr); /* size is set to top_of_tsr paragraphs */
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,6 +0,0 @@
|
||||
Installs file-sharing and locking capabilities on your hard disk.
|
||||
|
||||
SHARE [/F:space] [/L:locks]
|
||||
|
||||
/F:space Allocates file space (in bytes) for file-sharing information.
|
||||
/L:locks Sets the number of files that can be locked at one time.
|
Loading…
Reference in New Issue
Block a user