[net.lang.st80] Smalltalk Notes 2: Read-only files fix

rentsch@unc.UUCP (Tim Rentsch) (11/04/86)

Copyright(c) 1986, by Tim Rentsch

Copyright Notice:  This memo is Copyright(c) 1986, by Tim Rentsch.
Copies may be made and distributed provided all of the following
conditions are met:  one, the copyright notice be included in its
entirety; two, the memo be copied (or distributed) in its entirety;
three, the memo be copied (or distributed) individually, i.e., not in
collection with other material; four, copies be made and distributed
one at a time, i.e., copies cannot be made or distributed in batches
of more than one; five, copies may not be sold -- distributing copies
is to be done at no cost to the recipients of the copies.  (End of
conditions, and end of copyright notice.)  



Note # 2:  Read-Only Files
==========================

By now you have probably run smalltalk, and you may have noticed a
glaring deficiency.  Our version of PS had the property that it did
not correctly handle files which were read-only.  As near as I can
figure out this is due to a bug in the file opening primitive (I
don't have PS interpreter source code so who can say?).  While I
don't have a fix to the interpreter, I do have a work around.  The
filed out code follows.

(For those interested, the problem is that files when being opened
all have the "create if non-existant" mode bit turned on.  For some
reason trying to open read-only files using the smalltalk system call
primitive with this bit turned on fails.  The work around is to not
turn on the "create if non-existant" bit for files that already
exist.)  

You could try to read this in using a "file list";  if you do, don't
forget to choose "swap cr-lfs", as PS is confused about what a new
line is.  Rather than filing the code in, you could just put the
fixes in by hand, using the browser.  The main change is in 

   UnixFileStream | reopen

with one ancillary added method

  UnixFileStream class | createIfNonExistantMode

Of course if you are typing the code in by hand you could just put
the constant "in-line" as it were.  (Don't forget to use the
left-shift key when selecting methods if your '.sources' file is
read-only.)  

[Hopeful note -- we also have code which makes files understand
about unix new lines (and it produced this code here).  A future
note will contain this as a goodie.]

Note that the following has had tabs turned into 3 spaces to
accomodate the N x 80 format, as well as various other formatting
crocks.  Life is hard.  

The code follows after the ....

(End of Note # 2)


--------------------------------CUT HERE--------------------------------
'From UNC Smalltalk-80, version 2.1A, of November 1, 1986 on 3 November
 1986 at 11:33:33 pm'!



!UnixFileStream methodsFor: 'file status'!

reopen
   "Set the receiver to stream over an open file, setting the
   position to the preveous position."

   "fixed to work around file creation mode bit bug in system call primitives.
      october 11, 1986  -txr"

   | name fileExists canRead canWrite unixMode |
   collection == nil ifFalse: [^nil].
   name _ self fullName.
   fileExists _ UnixFileDirectory includesKey: name.
   canRead _ UnixFileDirectory canReadFile: name.
   canWrite _ UnixFileDirectory canWriteFile: name.
   canRead
      ifTrue:
         [canWrite
            ifTrue:
               [openMode _ #readWrite.
               unixMode _ self class readWriteMode]
            ifFalse:
               [openMode _ #readOnly.
               unixMode _ self class readOnlyMode]]
      ifFalse:
         [canWrite
            ifTrue:
               [openMode _ #writeOnly.
               unixMode _ self class writeOnlyMode]
            ifFalse:
               [^self error: name ,
                  ': permission denied, file can not be opened.']].
   fileExists ifTrue: [ unixMode _ unixMode bitAnd:
                          self class createIfNonExistantMode bitInvert ].
   collection _ (UnixSystemCall open: name for: unixMode mode: 8r644) value.

   openMode = #readOnly
      ifTrue:
         [readMode _ #readOnly].
   openMode = #writeOnly
      ifTrue:
         [(#(writeOnly writeShorten) includes: readMode)
            ifFalse:
               [readMode _ #writeOnly]].

   aFileBuffer _ UnixFileBuffer openForFileDescriptor: collection.
   FileDirectory addExternalReference: self! !


!UnixFileStream class methodsFor: 'read mode constants'!

createIfNonExistantMode
   "Answer the value for creating non-existant files on open mode."

   ^8r1000! !