home *** CD-ROM | disk | FTP | other *** search
-
-
-
-
- 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 done 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.
-
- 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 "<filename>" 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 for 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:
-
- <I> < S > <R> < 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 thing 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 required 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 we 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:
- <I> < S > <R> < 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:
- <I> < S > <R> < 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
- which is READ ACCESS, which allows us to read a READ-ONLY file.
-
- PCBoard is opening its DIR files as READ ACCESS SHARED are
- actually opening the file with a SHARING MODE of Deny/Write
- which would be a SHARE <S> field of 010. This number for the
- OpenModeByte then becomes:
- <I> < S > <R> < 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
- <S> or SHARING FIELD and would be coded 010. For READ/WRITE
- ACCESS the <A> 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:
-
- <I> < S > <R> < 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".
-
- 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:
- <I> < S > <R> < 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 --
-