home *** CD-ROM | disk | FTP | other *** search
/ Shareware Overload / ShartewareOverload.cdr / progm / tpshare.zip / TPSHARE.DOC < prev   
Text File  |  1987-01-19  |  19KB  |  561 lines

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