Dec 232017
 
File explaining how to perform file-sharing in Turbo P.
File TPSHARE1.ZIP from The Programmer’s Corner in
Category Pascal Source Code
File explaining how to perform file-sharing in Turbo P.
File Name File Size Zip Size Zip Type
TPSHARE1.DOC 19566 5452 deflated

Download File TPSHARE1.ZIP Here

Contents of the TPSHARE1.DOC file






Methods for Dealing with Shared Files in Turbo Pascal
by
John W. Wulff
The Peg Board BBS
703-349-8220
January 19, 1987


There have been many innovations in the development of PCBoard
software for BBS's. One of which is the network environment that
the authors have included in the code. While this is wonderful
for the multi-node system, it does pose certain problems and
restrictions on application programs and utilities that are being
written for it, especially those written in Borland's Turbo
Pascal. Foremost among these problems is the inability of Turbo
Pascal, henceforth known as TP, to deal with Read-Only attribute
files. After an ASSIGN(OpenFile,FileName), doing a simple
RESET(OpenFile) will result in a 'File Not Found' error, even
though you only want to read from the file. This is because TP
opens all files in what is known as "Inherited by Child Processes,
Compatibility Mode, Read/Write access". This will also cause a
Sharing violation if running under a DOS 3.x networking mode.

I have written a utility for PCBoard systems, PCBFile, and since
it is extremely file intensive, I've had to do some research on
the technical aspects of DOS 3.x in the network mode. Because of
this research, I've been able to get TP to cooperate and have
written this paper to help other authors who are struggling with
the same problems.

Bela Lubkin published a text article, ACMODE.DOC, which is on
Compuserve in the Borland Sig that gives the locations of a
little gem known as the "Open Mode Byte". This byte is at an
absolute address for the various editions of TP and communicates
to DOS, via Function call 3DH, how the file is to be accessed
and what access to give other processes. It also becomes very
handy for us in trying to use TP in a network environment.
These locations are:












-- 1 --


Open mode byte for Reset & Rewrite for Turbo 3.00x (PC-DOS)
TURBO.COM CSEG:$248D
TURBO-87.COM CSEG:$1F3C
TURBOBCD.COM CSEG:$2393

Open mode byte for Reset & Rewrite for Turbo 3.00x (MS-DOS)
TURBO.COM CSEG:$2182
TURBO-87.COM CSEG:$1C31
TURBOBCD.COM CSEG:$2088

Open mode byte for Reset & Rewrite for Turbo 3.01x (PC-DOS)
TURBO.COM CSEG:$24FC
TURBO-87.COM CSEG:$1FAB
TURBOBCD.COM CSEG:$2402

Open mode byte for Reset & Rewrite for Turbo 3.01x (MS-DOS)
TURBO.COM CSEG:$21D4
TURBO-87.COM CSEG:$1C83
TURBOBCD.COM CSEG:$20DA

Open mode byte for Reset & Rewrite for Turbo 3.02x (PC-DOS)
TURBO.COM CSEG:$24C6
TURBO-87.COM CSEG:$1F75
TURBOBCD.COM CSEG:$23CE





























-- 2 --



Another valuable document is Robert K. Blaine's RES_MODE.INC,
also available on CSERV. It details the procedure for finding
out the location of this byte, using DEBUG.

As profiled in the above documents, TP opens a file for RESET or
REWRITE with a 2 in this byte location. The docs suggest that
you should load the location with a 0 to RESET or REWRITE read-
only files. While this works for READ-ONLY files, it is not the
only value to consider when running an application in a network
environment, especially one with PCBoard software which I will
focus my attention for the remainder of the document.

One thing to consider, if using other languages, especially
assembly language, this Open Mode Byte, corresponds to the AL
register. All references to that byte and its decimal number
can be applied to assembly in this way:
AH contains 3DH - the function call
DS:DX points to an ASCIIZ path name
AL will be loaded with the 8 bit number that the
OpenModeByte variable contains.
When the function returns, AX will contain error codes or a 16
bit file handle is successful. (See DOS manual for details)
I don't profess to be anywhere close to fluent in assembly so I
will leave this information with those who are best suited to
take advantage of it.

It is suggested that this byte be accessed by creating an
absolute variable in your program pointing to the byte:

Var
OpenModeByte: Byte Absolute CSeg:$24FC; {PC-DOS Turbo 3.01}

Then a simple check is necessary to see if the byte contains a 2
and if so, load it with a 0:

begin
if OpenModeByte = 2 then
OpenModeByte := 0;
end;

The completed routine would look like this:











-- 3 --




Procedure OpenMode(Var OpenFile : text;
InFileName : fname; { typed globally as
string[64] }
Var GoAhead : boolean);

var
OpenModeByte : Byte Absolute CSeg:$24FC; (* TURBO 3.01 *)

begin
if OpenModeByte = 2 then
OpenModeByte := 0; (* allows reading of READ-ONLY files *)
assign(OpenFile,InFileName);
{$I-} reset(Openfile) {$I+};
GoAhead := (ioresult = 0);
if GoAhead then
writeln(InFileName,' opened!')
else
writeln(InFileName,' failed to open!');
end; { OpenMode }

Now we need to determine just what is going on with PCBoard and
how it opens files using DOS's SHARE.

The DIR files, or the files that contain the filenames of the
available files for the user to download, are opened in READ
SHARED mode which in QuickBASIC would be:

OPEN "" FOR INPUT ACCESS READ SHARED AS #1.

Upload DIR files are opened for APPEND in a LOCKED WRITE mode.
This keeps other nodes from writing at that particular moment
but allows other nodes to read this file.

In order to accomplish these same modes in TP we must look into
the DOS 3.1 Technical Reference Manual (groan!). The following
is reprinted from that manual with some additions by me.

The OPEN mode consists of 4 bit-oriented fields:

* INHERITANCE FLAG
* SHARING MODE FIELD
* RESERVED FIELD
* ACCESS FIELD

The INHERITANCE FLAG determines if the file will ever be
inherited by another process, which in the case of a network is
usually the desired effect. The SHARING FIELD defines what




-- 4 --

operations may be performed on the file by other nodes. The
ACCESS FIELD defines what operations THIS node may perform on
the file. The bit fields are mapped as follows:

< S > < A >
Open Mode bits 7 6 5 4 3 2 1 0

I INHERITANCE FLAG
If I = 0; File is inherited by child processes
If I = 1; File is private to the current process

S SHARING MODE
The file is opened like this:
if S = 000; Compatibility mode - The default open mode it
denies ALL OTHER processes access to the file.
Since this is the mode that TP uses to open a
file, what do you think will happen on the BBS
side if you have a file open on your end and the
BBS tries to open it?
if S = 001; Deny Read/Write mode (Exclusive). This would
actually be the same as setting the I flag to 1.
if S = 010; Deny Write mode - you should open a file in this
mode if you wish to protect it. It will allow
other processes to read it but not write.
if S = 011; Deny Read mode
if S = 100; Deny None mode - Who cares what happens!

It is important to specify what operations you want to
perform (access mode). The default access mode is Read/Write
and causes the open request to fail if another process has
the file opened with any sharing mode other than Deny None.
File sharing requires cooperation of both sharing processes.
This is communicated through the sharing and access modes.

R RESERVED (set third bit field to 0)

A ACCESS - The file access is assigned as follows:

If A = 000; Read Access
if A = 001; Write Access
if A = 010; Read/Write access

If all this seems a bit involved, I'm sorry. I don't know of
any way to give you the background for all this hocus-pocus
except with the above info. I also recommend picking up a Tech
Ref manual for more detailed study of the 3DH function call.

OK! With all these numbers in hand, let's see how to get TP to
duplicate these modes. Earlier I said that other gurus had
stated that TP opens files in Compatibility Mode with Read/Write




-- 5 --

Access and Inheritance by child processes and the magic number
of the Open Mode byte is 2. Let's look at how that was done:
Compatibility mode: 000 {S}
Read/Write ACCESS : 010 {A}
Inherited by child: 0 {I}
Reserved is ALWAYS: 0 {R}

Remember the bit fields are:
< S > < A >
Open Mode bits 7 6 5 4 3 2 1 0 Let's plug in
0 0 0 0 0 0 1 0 the numbers.
Using binary arithmetic:
< S > < A >
128 64 32 16 8 4 2 1
0 0 0 0 0 0 1 0 = 00000010 = 2

By using an OpenModeByte of 0 we change the ACCESS field to 000,
READ ACCESS, which allows us to read a READ-ONLY file.

PCBoard is opening its DIR files as READ ACCESS SHARED and
actually opening the file with a SHARING MODE of Deny/Write
which would be a SHARE field of 010. This number for the
OpenModeByte then becomes:
< S > < A >
128 64 32 16 8 4 2 1
0 0 1 0 0 0 0 0 = 00100000 = 32

This is how I open ALL my files for reading or for general
ASSIGNING for RESET in TP for my program PCBFile. I have some
procedures written for TEXT files, and files of type BYTE.

I have reproduced the code below:


(* This procedure, KeepOn, is used to determine if the file has
been locked out. I try a file for 10 times as determined by
OpenAtt variable before I give up *)

Procedure KeepOn(OpenAtt : byte; var GA : boolean);
begin
if OpenAtt <= 10 then
GA := TRUE (* GoAhead Flag - if within 10 go for it *)
else GA := FALSE; (* forget it! *)
end;










-- 6 --



Procedure SetResetMode(Var OpenFile : text; (* OPEN MODE FOR
InFileName : fname; TEXT FILES *)
var GoAhead : boolean);
var
OpenModeByte : Byte Absolute CSeg:$24FC;
OpenAttempts : byte;
begin
OpenAttempts := 1;
if OpenModeByte = 2 then
OpenModeByte := 32; (* this is Deny Write Mode/Read Access *)
assign(OpenFile,InFileName);
repeat
{$I-} reset(Openfile) {$I+};
GoAhead := (ioresult = 0);
if not GoAhead then
OpenAttempts := OpenAttempts + 1;
until (GoAhead) OR (OpenAttempts > 10); (* try until I get in *)
KeepOn(OpenAttempts,GoAhead);
end; { SetResetMode }

Procedure SetResetModeFile(Var OpenFile : bytefile;(* bytefile *)
InFileName : fname; (* previously *)
var GoAhead : boolean); (* typed as *)
(* File of Byte *)
var
OpenModeByte : Byte Absolute CSeg:$24FC;
OpenAttempts : byte;
begin
OpenAttempts := 1;
if OpenModeByte = 2 then
OpenModeByte := 32; (* this is Deny Write Mode/Read Access *)
assign(OpenFile,InFileName);
repeat
{$I-} reset(Openfile) {$I+};
GoAhead := (ioresult = 0);
if not GoAhead then
OpenAttempts := OpenAttempts + 1;
until GoAhead OR (OpenAttempts > 10);
KeepOn(OpenAttempts,GoAhead);
end; { SetResetModeFile }












-- 7 --


************************************************************
Now here comes a little zinger to change things up. I want to
create a file that I don't want the other nodes to damage. I
elect to open the file for READ/WRITE ACCESS for myself and
give the other nodes READ capability and deny them the ability
to write to my file. This would be Deny/Write Mode under the
or SHARING FIELD and would be coded 010. For READ/WRITE
ACCESS the or ACCESS FIELD is coded 010 also. This is the
same mode that PCBoard uses for writing to the Upload directory.
Using our binary formulae, OpenModeByte then becomes:

< S > < A >
128 64 32 16 8 4 2 1
0 0 1 0 0 0 1 0 = 00100010 = 34

With the magic number of 34 the SetFileLock procedure was born.

Procedure SetFileLock(Var OpenFile : buftext;
InFileName : fname;
var GoAhead : boolean);
var
OpenModeByte : Byte Absolute CSeg:$24FC;
OpenAttempts : byte;

begin
OpenAttempts := 1;
if OpenModeByte = 2 then
OpenModeByte := 34; (* Deny Write Mode/Read-Write Access *)
assign(OpenFile,InFileName);
repeat
{$I-} rewrite(Openfile) {$I+};
GoAhead := (ioresult = 0);
if not GoAhead then
OpenAttempts := OpenAttempts + 1;
until GoAhead or (OpenAttempts > 10);
KeepOn(OpenAttempts,GoAhead);
end; { SetLockMode }

Finally, a little walk around the park to insure that the
OpenModeByte is returned to Borland's normal mode.

Procedure ReleaseOpenMode;
var
OpenModeByte : Byte Absolute CSeg:$24FC;
begin
OpenModeByte := 2;
end;

So it's really simple to change Turbo Pascal Open mode to




-- 8 --

exactly what you want, you just have to know what mode you
desire the program to work in. Just remember these definitions
of the fields that make up the magic number for DOS Function
call 3DH.

* INHERITANCE FLAG I = 0; Inherited (usually the case)
I = 1; Private

* SHARING MODE FIELD (Other node or process)
S = 000; Compatibility mode
S = 001; Deny Read/Write mode (Exclusive)
S = 010; Deny Write mode
S = 011; Deny Read mode
S = 100; Deny None mode

* RESERVED FIELD R = 0; Always

* ACCESS FIELD (Your node or process)
A = 000; Read Access
A = 001; Write Access
A = 010; Read/Write Access

The bit fields:
< S > < A >
Open Mode bits 7 6 5 4 3 2 1 0





























-- 9 --



Even though the DOS 3.1 Technical Reference Manual gives a more
thorough discussion of Function Call 3DH, I will attempt to
create a matrix with the number for the OpenModeByte based on
the SHARE and ACCESS fields.

ACCESS |SHARE-> Compat Deny/RW Deny/W Deny/R Deny/N
| 000 001 010 011 100
v -------------------------------------------
Read 000 | 0 | 16 | 32 | 48 | 64 |
|--------|-------|-------|-------|--------|
Write 001 | 1 | 17 | 33 | 49 | 65 |
|--------|-------|-------|-------|--------|
Read/ 010 | 2 | 18 | 34 | 50 | 66 |
Write -------------------------------------------

I know that this is probably more than a human can bear to
assimilate at any one time but I hope that you will be able to
see the logic behind my system and be able to use Turbo Pascal
to its full potential.


PCBoard (c) Clark Development Company, Inc., Murray, UT
Turbo Pascal (c) Borland International, Scotts Valley, CA
PCBFile (c) John W. Wulff
Compuserve (c) Compuserve, Inc., Columbus, OH



























-- 10 --



Leave a Reply