home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PASCAL / TPSHARE5.ZIP / TPSHARE5.TXT
Encoding:
Text File  |  1989-05-15  |  20.4 KB  |  529 lines

  1.  
  2.  
  3.  
  4.  
  5.  
  6.  
  7.  
  8.                         Methods for Dealing with Shared Files
  9.                              in TURBO Pascal Version 5.0
  10.                                           by
  11.                                     John W. Wulff
  12.                                Wulff Enterprises, Inc.
  13.                                  260 Terranova Drive
  14.                               Warrenton, VA  22186-9227
  15.                                     (703) 349-8805
  16.  
  17.                                  Revised May 15, 1989
  18.            
  19.           This paper was first written January 19, 1987 as a means of
  20.           demonstrating how to modify Turbo Pascal 3.x to handle the
  21.           opening of READ-ONLY files and to make it able to deal with files
  22.           in a Shared, network environment.  It provided a means of finding
  23.           an undocumented byte known as the "Open Mode Byte".  Since then,
  24.           Turbo Pascal 5.0 has been released and this byte has been
  25.           globally declared as the FILEMODE variable.  Even so, Turbo
  26.           Pascal 5.0 ignores the variable when opening TEXT files.  While
  27.           there is a small explanation in the Turbo Pascal Reference Guide
  28.           as to its use, the information in this paper is still valid today
  29.           and has been updated to reflect its relevance to Turbo Pascal
  30.           5.0.  For those wishing to continue to work in Turbo Pascal 3.0,
  31.           I have included the locations for this byte in appendix A.
  32.  
  33.           There have been many innovations in the development of PCBoard
  34.           software for BBS's.  One of which is the network environment that
  35.           the authors have included in the code.  While this is wonderful
  36.           for the multi-node system, it does pose certain problems and
  37.           restrictions on application programs and utilities that are being
  38.           written for it, especially those written in Borland's Turbo
  39.           Pascal.
  40.  
  41.           One problem that plagues most authors writing application
  42.           programs that eventually become used in network environments is
  43.           coping with the Share utility that DOS uses to protect files. 
  44.           Any file opened for reading under Turbo Pascal will cause a
  45.           Sharing violation if running under a DOS 3.x and 4.x networking
  46.           mode.  This is because Turbo Pascal opens all files in what is
  47.           known as "Inherited by Child Processes, Compatibility Mode,
  48.           Read/Write access". 
  49.  
  50.           I have written a utility for PCBoard systems, PCBFile, and since
  51.           it is extremely file intensive, I've had to do some research on
  52.           the technical aspects of DOS in the network mode.  Because of
  53.           this research, I've been able to get Turbo Pascal to cooperate
  54.           and have written this paper to help other authors who are
  55.           struggling with the same problems.
  56.  
  57.           As documented in the Turbo Pascal instructions, the FILEMODE
  58.           variable has a value of 2 when opening files for RESET or REWRITE
  59.           which allows both reading and writing.  The instructions suggest
  60.           that you should assign a value of 0 to the variable to RESET or
  61.           REWRITE read-only files.  While this works for READ-ONLY files,
  62.  
  63.  
  64.  
  65.  
  66.  
  67.  
  68.  
  69.  
  70.  
  71.  
  72.  
  73.  
  74.  
  75.           it is not the only value to consider when running an application
  76.           in a network environment, especially one with PCBoard software
  77.           upon which I will focus my attention for the remainder of the
  78.           document.
  79.            
  80.           One thing to consider, if using other languages, especially
  81.           assembly language, is that this FILEMODE variable, corresponds to
  82.           the AL register.  All references to that byte and its decimal
  83.           number can be applied to assembly in this way: 
  84.  
  85.                  AH contains 3DH - the function call 
  86.                  DS:DX points to an ASCIIZ path name 
  87.                  AL will be loaded with the 8 bit number that the          
  88.                  FILEMODE variable contains. 
  89.  
  90.           When the function returns, AX will contain error codes or a 16
  91.           bit file handle if successful.  (See DOS manual for details.)  I
  92.           don't profess to be anywhere close to fluent in assembly so I
  93.           will leave this information with those who are best suited to
  94.           take advantage of it. 
  95.  
  96.           This variable is GLOBALLY pre-declared in Turbo Pascal, so all
  97.           you have to do is refer to it as FILEMODE.  Then a simple check
  98.           is necessary to see if the variable contains a 2 and if so, load
  99.           it with a 0: 
  100.            
  101.                          begin 
  102.                            if FILEMODE = 2 then 
  103.                              FILEMODE := 0; 
  104.                          end;
  105.  
  106.           The completed routine would look like this:  
  107.  
  108.           Procedure OpenMode(Var OpenFile : text; 
  109.                                InFileName : string
  110.                              Var GoAhead  : boolean); 
  111.  
  112.           {Remember, FILEMODE is a GLOBALLY declared variable of type
  113.            byte.  No other declaration is necessary on your part}
  114.  
  115.           begin 
  116.             if FILEMODE = 2 then 
  117.               FILEMODE := 0; (* allows reading of READ-ONLY files *) 
  118.             assign(OpenFile,InFileName); 
  119.             {$I-} reset(Openfile) {$I+}; 
  120.             GoAhead := (ioresult = 0);   
  121.             if GoAhead then 
  122.               writeln(InFileName,' opened!') 
  123.             else 
  124.               writeln(InFileName,' failed to open!'); 
  125.           end; { of Procedure OpenMode } 
  126.  
  127.  
  128.           Shared Files in Turbo Pascal 5.0                                2
  129.  
  130.  
  131.  
  132.  
  133.  
  134.  
  135.  
  136.  
  137.  
  138.  
  139.  
  140.  
  141.  
  142.           Now we need to determine just what is going on with PCBoard and
  143.           how it opens files using DOS's SHARE.   The DIR files, or the
  144.           files that contain the filenames of the available files for the
  145.           user to download, are opened in READ SHARED mode which in
  146.           QuickBASIC would be: 
  147.  
  148.               OPEN "<filename>" FOR INPUT ACCESS READ SHARED AS #1.   
  149.  
  150.           Upload DIR files are opened for APPEND in a LOCKED WRITE mode.
  151.           This keeps other nodes from writing at that particular moment but
  152.           allows other nodes to read this file.
  153.  
  154.           In order to accomplish these same modes in Turbo Pascal we must
  155.           look into the DOS Technical Reference Manual (groan!).  The
  156.           following is reprinted from that manual with some additions by
  157.           me.
  158.  
  159.           The OPEN mode consists of 4 bit-oriented fields:     
  160.                * INHERITANCE FLAG
  161.                * SHARING MODE FIELD 
  162.                * RESERVED FIELD 
  163.                * ACCESS FIELD   
  164.           The INHERITANCE FLAG determines if the file will ever be
  165.           inherited by another process, which in the case of a network is
  166.           usually the desired effect.  The SHARING FIELD defines what
  167.           operations may be performed on the file by other nodes.  The
  168.           ACCESS FIELD defines what operations THIS node may perform on the
  169.           file.  
  170.  
  171.           The bit fields are mapped as follows: 
  172.                               <I> < S > <R> < A > 
  173.              Open Mode bits    7  6 5 4  3  2 1 0 
  174.           I  INHERITANCE FLAG 
  175.              If I = 0; File is inherited by child processes 
  176.              If I = 1; File is private to the current process 
  177.  
  178.           S  SHARING MODE 
  179.              The file is opened like this:
  180.              if S = 000;  Compatibility mode - The default open mode - it
  181.                           denies ALL OTHER processes access to the file. 
  182.                           Since this is the mode that Turbo Pascal uses to
  183.                           open a file, what do you think will happen on the
  184.                           BBS side if you have a file open on your end and
  185.                           the BBS tries to open it? 
  186.              if S = 001;  Deny Read/Write mode (Exclusive).  This would
  187.                           actually be the same as setting the I flag to 1. 
  188.              if S = 010;  Deny Write mode - you should open a file in this
  189.                           mode if you wish to protect it.  It will allow
  190.                           other processes to read it but not write.
  191.              if S = 011;  Deny Read mode 
  192.              if S = 100;  Deny None mode - Who cares what happens!
  193.  
  194.  
  195.           Shared Files in Turbo Pascal 5.0                                3
  196.  
  197.  
  198.  
  199.  
  200.  
  201.  
  202.  
  203.  
  204.  
  205.  
  206.  
  207.  
  208.  
  209.           It is important to specify what operations you want to perform
  210.           (access mode).  The default access mode is Read/Write and causes
  211.           the open request to fail if another process has the file opened
  212.           with any sharing mode other than Deny None.  File sharing
  213.           requires cooperation of both sharing processes.  This is
  214.           communicated through the sharing and access modes.
  215.  
  216.           R  RESERVED (set third bit field to 0)
  217.  
  218.           A  ACCESS - The file access is assigned as follows:
  219.  
  220.              If A = 000; Read Access 
  221.              if A = 001; Write Access 
  222.              if A = 010; Read/Write access
  223.  
  224.           If all this seems a bit involved, I'm sorry.  I don't know of any
  225.           way to give you the background for all this hocus-pocus except
  226.           with the above info.  I also recommend picking up a Tech Ref
  227.           manual for more detailed study of the 3DH function call.
  228.  
  229.           OK!  With all these numbers in hand, let's see how to get Turbo
  230.           Pascal to duplicate these modes.  Earlier I said that other gurus
  231.           had stated that Turbo Pascal opens files in COMPATIBILITY MODE
  232.           with READ/WRITE ACCESS and INHERITANCE BY CHILD PROCESSES and the
  233.           magic value for the FILEMODE variable is 2.  Let's look at how
  234.           that was done:
  235.  
  236.                Compatibility mode:   000 {S} 
  237.                Read/Write ACCESS :   010 {A} 
  238.                Inherited by child:     0 {I} 
  239.                Reserved as ALWAYS:     0 {R} 
  240.            
  241.           Remember the bit fields are: 
  242.                               <I> < S > <R> < A > 
  243.              Open Mode bits    7  6 5 4  3  2 1 0  Let's plug in 
  244.                                0  0 0 0  0  0 1 0  the numbers. 
  245.           Using binary arithmetic: 
  246.                               <I> <  S   > <R> < A >
  247.                               128 64 32 16  8  4 2 1
  248.                                0   0  0  0  0  0 1 0 = 00000010 = 2 
  249.             
  250.           By using a FILEMODE value of 0 we change the ACCESS field to 000,
  251.           READ ACCESS, which allows us to read a READ-ONLY file.
  252.            
  253.           PCBoard is opening its DIR files as READ ACCESS SHARED and
  254.           actually opening the file with a SHARING MODE of Deny/Write which
  255.           would be a SHARE <S> field of 010.  The value for the FILEMODE
  256.           variable then becomes: 
  257.                               <I> <  S   > <R> < A > 
  258.                               128 64 32 16  8  4 2 1 
  259.                                0   0  1  0  0  0 0 0 = 00100000 = 32
  260.  
  261.  
  262.           Shared Files in Turbo Pascal 5.0                                4
  263.  
  264.  
  265.  
  266.  
  267.  
  268.  
  269.  
  270.  
  271.  
  272.  
  273.  
  274.  
  275.  
  276.           This is how I open ALL my files for reading or for general
  277.           ASSIGNING for RESET in Turbo Pascal for my program PCBFile.  I
  278.           have some procedures written for TEXT files, and files of type
  279.           BYTE.  I have reproduced the code below:  
  280.           (* This procedure, KeepOn, is used to determine if the file has 
  281.           been locked out.  I try a file for 10 times as determined by 
  282.           OpenAtt variable before I give up  *) 
  283.            
  284.           Procedure KeepOn(OpenAtt : byte; var GA : boolean); 
  285.           begin 
  286.             if OpenAtt <= 10 then 
  287.               GA := TRUE      (* GoAhead Flag - if within 10 go for it *) 
  288.             else GA := FALSE;    (* forget it! *) 
  289.           end; {of Procedure KeepOn}
  290.            
  291.           Procedure SetResetMode(Var OpenFile : text;  (* OPEN MODE FOR
  292.                                  InFileName   : string;    TEXT FILES *) 
  293.                                   Var GoAhead : boolean); 
  294.           var
  295.             OpenAttempts  : byte; 
  296.  
  297.           begin 
  298.             OpenAttempts := 1; 
  299.             FILEMODE := 32;         (* this is Deny Write                  
  300.                                        Mode/Read Access *) 
  301.             assign(OpenFile,InFileName); 
  302.             repeat 
  303.               {$I-} reset(Openfile) {$I+}; 
  304.               GoAhead := (ioresult = 0); 
  305.               if not GoAhead then 
  306.                 OpenAttempts := OpenAttempts + 1; 
  307.             until (GoAhead) OR (OpenAttempts > 10); (* keep trying *) 
  308.             KeepOn(OpenAttempts,GoAhead); 
  309.           end; {of Procedure SetResetMode} 
  310.            
  311.           Procedure SetResetModeFile(Var OpenFile : file of byte 
  312.                                      InFileName   : string;                
  313.                                       var GoAhead : boolean);             
  314.           var 
  315.             OpenAttempts  : byte; 
  316.           begin 
  317.             OpenAttempts := 1; 
  318.             if FILEMODE := 32;   (* this is Deny Write                     
  319.                                   Mode/Read Access *)    
  320.           assign(OpenFile,InFileName); 
  321.             repeat 
  322.               {$I-} reset(Openfile) {$I+}; 
  323.               GoAhead := (ioresult = 0); 
  324.               if not GoAhead then OpenAttempts := OpenAttempts + 1; 
  325.             until GoAhead OR (OpenAttempts > 10); 
  326.             KeepOn(OpenAttempts,GoAhead); 
  327.           end; {of Procedure SetResetModeFile}
  328.  
  329.           Shared Files in Turbo Pascal 5.0                                5
  330.  
  331.  
  332.  
  333.  
  334.  
  335.  
  336.  
  337.  
  338.  
  339.  
  340.  
  341.  
  342.  
  343.  
  344.           Now here comes a little zinger to change things up.  I want to
  345.           create a file that I don't want the other nodes to damage.  I
  346.           elect to open the file for READ/WRITE ACCESS for myself and give
  347.           the other nodes READ capability and deny them the ability to
  348.           write to my file.  This would be Deny/Write Mode under the <S> or
  349.           SHARING FIELD and would be coded 010.  For READ/WRITE ACCESS the
  350.           <A> or ACCESS FIELD is coded 010 also.  This is the same mode
  351.           that PCBoard uses for writing to the Upload directory.  Using our
  352.           binary formulae, the FILEMODE value then becomes: 
  353.                               <I> <  S   > <R> < A > 
  354.                               128 64 32 16  8  4 2 1 
  355.                                0   0  1  0  0  0 1 0 = 00100010 = 34 
  356.  
  357.           With the magic number of 34 the SetFileLock procedure was born.
  358.            
  359.           Procedure SetFileLock(Var   OpenFile : text;
  360.                                     InFileName : string; 
  361.                                    var GoAhead : boolean); 
  362.           var 
  363.             OpenAttempts  : byte;  
  364.  
  365.           begin 
  366.             OpenAttempts := 1; 
  367.             FILEMODE := 34;      (* Deny Write Mode/Read-Write Access *) 
  368.             assign(OpenFile,InFileName); 
  369.             repeat 
  370.               {$I-} rewrite(Openfile) {$I+}; 
  371.               GoAhead := (ioresult = 0); 
  372.               if not GoAhead then 
  373.                 OpenAttempts := OpenAttempts + 1; 
  374.             until GoAhead or (OpenAttempts > 10); 
  375.             KeepOn(OpenAttempts,GoAhead); 
  376.           end; {of Procedure SetFileLock}
  377.            
  378.           Finally, a little walk around the park to insure that the
  379.           FILEMODE variable is returned to Borland's normal mode.
  380.  
  381.           Procedure ReleaseOpenMode; 
  382.  
  383.           begin 
  384.             FILEMODE := 2; 
  385.           end; 
  386.  
  387.           So it's really simple to change the Turbo Pascal Open mode to
  388.           exactly what you want, you just have to know what results you
  389.           desire from the program.  Just remember these definitions of the
  390.           fields that make up the magic number for DOS Function call 3DH. 
  391.            
  392.           * INHERITANCE FLAG       I = 0;   Inherited (usually the case) 
  393.                                    I = 1;   Private
  394.  
  395.  
  396.           Shared Files in Turbo Pascal 5.0                                6
  397.  
  398.  
  399.  
  400.  
  401.  
  402.  
  403.  
  404.  
  405.  
  406.  
  407.  
  408.  
  409.  
  410.           * SHARING MODE FIELD     (Other node or process)
  411.                                    S = 000; Compatibility mode 
  412.                                    S = 001; Deny Read/Write mode           
  413.                                    (Exclusive) 
  414.                                    S = 010; Deny Write mode 
  415.                                    S = 011; Deny Read mode 
  416.                                    S = 100; Deny None mode 
  417.  
  418.           * RESERVED FIELD         R = 0; Always 
  419.  
  420.           * ACCESS FIELD           (Your node or process) 
  421.                                    A = 000; Read Access 
  422.                                    A = 001; Write Access 
  423.                                    A = 010; Read/Write Access
  424.           The bit fields: 
  425.                                    <I> < S > <R> < A >
  426.                   Open Mode bits    7  6 5 4  3  2 1 0 
  427.            
  428.           Even though a DOS Technical Reference Manual gives a more
  429.           thorough discussion of Function Call 3DH, I will attempt to
  430.           create a matrix with the number for the FILEMODE variable based
  431.           on the SHARE and ACCESS fields. 
  432.            
  433.             ACCESS   |SHARE-> Compat  Deny/RW  Deny/W  Deny/R  Deny/N 
  434.              |                 000      001     010     011     100 
  435.              v              ------------------------------------------- 
  436.             Read  000       |   0    |   16  |   32  |   48  |   64   | 
  437.                             |--------|-------|-------|-------|--------| 
  438.             Write 001       |   1    |   17  |   33  |   49  |   65   | 
  439.                             |--------|-------|-------|-------|--------| 
  440.             Read/ 010       |   2    |   18  |   34  |   50  |   66   | 
  441.             Write           ------------------------------------------- 
  442.            
  443.           I know that this is probably more than a human can bear to
  444.           assimilate at any one time but I hope that you will be able to
  445.           see the logic behind my system and be able to use Turbo Pascal to
  446.           its full potential.  
  447.            
  448.           PCBoard (c) Clark Development Company, Inc., Murray, UT 
  449.           Turbo Pascal (c) Borland International, Scotts Valley, CA 
  450.           PCBFile (c) John W. Wulff 
  451.           Compuserve (c) Compuserve, Inc., Columbus, OH 
  452.  
  453.  
  454.  
  455.  
  456.  
  457.  
  458.  
  459.  
  460.  
  461.  
  462.  
  463.           Shared Files in Turbo Pascal 5.0                                7
  464.  
  465.  
  466.  
  467.  
  468.  
  469.  
  470.  
  471.  
  472.  
  473.  
  474.  
  475.  
  476.  
  477.  
  478.                                        Appendix
  479.  
  480.           For Turbo Pascal 3.x Die-Hards:
  481.  
  482.           Bela Lubkin published a text article, ACMODE.DOC, which is on
  483.           Compuserve in the Borland Sig that gives the locations of a
  484.           little gem known as the "Open Mode Byte".  This byte is at an
  485.           absolute address for the various editions of Turbo Pascal and
  486.           communicates to DOS, via Function call 3DH, how the file is to be
  487.           accessed and what access to give other processes.  It also
  488.           becomes very handy for us in trying to use Turbo Pascal in a
  489.           network environment. These locations are:
  490.                Open mode byte for Reset & Rewrite for Turbo 3.00x (PC-DOS) 
  491.                     TURBO.COM      CSEG:$248D 
  492.                     TURBO-87.COM   CSEG:$1F3C 
  493.                     TURBOBCD.COM   CSEG:$2393 
  494.               Open mode byte for Reset & Rewrite for Turbo 3.00x (MS-DOS) 
  495.                     TURBO.COM      CSEG:$2182 
  496.                     TURBO-87.COM   CSEG:$1C31 
  497.                     TURBOBCD.COM   CSEG:$2088 
  498.               Open mode byte for Reset & Rewrite for Turbo 3.01x (PC-DOS) 
  499.                     TURBO.COM      CSEG:$24FC 
  500.                     TURBO-87.COM   CSEG:$1FAB 
  501.                     TURBOBCD.COM   CSEG:$2402 
  502.               Open mode byte for Reset & Rewrite for Turbo 3.01x (MS-DOS) 
  503.                     TURBO.COM      CSEG:$21D4 
  504.                     TURBO-87.COM   CSEG:$1C83 
  505.                     TURBOBCD.COM   CSEG:$20DA 
  506.               Open mode byte for Reset & Rewrite for Turbo 3.02x (PC-DOS) 
  507.                     TURBO.COM      CSEG:$24C6 
  508.                     TURBO-87.COM   CSEG:$1F75 
  509.                     TURBOBCD.COM   CSEG:$23CE 
  510.            
  511.           Another valuable document is Robert K. Blaine's RES_MODE.INC,
  512.           also available on CSERV.  It details the procedure for finding
  513.           out the location of this byte, using DEBUG.
  514.  
  515.  
  516.  
  517.  
  518.  
  519.  
  520.  
  521.  
  522.  
  523.  
  524.  
  525.  
  526.  
  527.  
  528.  
  529.  
  530.           Shared Files in Turbo Pascal 5.0                                8
  531.  
  532.  
  533.  
  534.  
  535.  
  536.  
  537.