Difference between revisions of "File access"
m (1 revision) |
(Added ZNOS) |
||
(11 intermediate revisions by 2 users not shown) | |||
Line 114: | Line 114: | ||
before using it: | before using it: | ||
− | IF dfs% THEN access%=(access% OR | + | IF dfs% THEN access%=(access% OR 3)EOR(access% DIV 4) |
+ | or | ||
+ | IF dfs% THEN access%=access% DIV 4 * 3 + 3 | ||
This changes: | This changes: | ||
− | ---- to - | + | ---- to --WR and L--- to L--R |
===Writing the access byte=== | ===Writing the access byte=== | ||
Line 126: | Line 128: | ||
Writing &00 (----) results in Unlocked | Writing &00 (----) results in Unlocked | ||
− | Writing & | + | Writing &02 (--W-) results in Locked |
Writing &08 (L---) results in Locked | Writing &08 (L---) results in Locked | ||
Line 186: | Line 188: | ||
===DOS=== | ===DOS=== | ||
− | + | <div class="mw-widebody"> | |
+ | | | | | RISC OS | RISC OS | | ||
+ | | Petrov DOSFS | Sprow DOSFS | LanManFS<ref>Sprow Ethernet Module https://chrisacorns.computinghistory.org.uk/docs/Sprow/masternet.pdf</ref> | DOSFS<ref>From investigation with RISC OS 3.11</ref> |Win95FS<ref>From investigation with RISC OS 3.11</ref>| OSFILE | ||
+ | +--------------+------------------+------------------+----------+----------+------------+ | ||
+ | | 1 | 1 | 1 | 1 | 1 | -> Owner R | ||
+ | | NOT ReadOnly | NOT ReadOnly | NOT ReadOnly | 1 | 1 | -> Owner W | ||
+ | | 0 | 0 | 0 | 0 | 0 | -> Owner E | ||
+ | | System | System OR Hidden | System OR Hidden | ReadOnly | ReadOnly | -> Owner L | ||
+ | | 1 | 0 | 1 | 0 | 1 | -> Public R | ||
+ | | NOT ReadOnly | 0 | NOT ReadOnly | 0 | 1 | -> Public W | ||
+ | | 0 | 0 | 0 | 0 | 0 | -> Public E | ||
+ | | 0 | 0 | 0 | 0 | 0 | -> Public L | ||
+ | | | | | System | System | -> attr b8 | ||
+ | | | | | Hidden | Hidden | -> attr b9 | ||
+ | | | | | Archive | Archive | -> attr b10 | ||
+ | this can be done with the following code: | ||
+ | acc%=&33-&22*(dosacc% AND 1)+2*(dosacc% AND 4) :REM Petrov | ||
+ | acc%=&0B-&02*(dosacc% AND 1)-8*((dosacc% AND 6)=0) :REM Sprow | ||
+ | acc%=&3B-&22*(dosacc% AND 1)-8*((dosacc% AND 6)=0) :REM LanManFS | ||
+ | acc%=&0B-8*(dosacc% AND 1) :REM DOSFS | ||
+ | acc%-&3B-8*(dosacc% AND 1) :REM Win95FS | ||
+ | |||
+ | | | | | RISC OS | RISC OS | | ||
+ | | Petrov DOSFS | Sprow DOSFS | LanManFS | DOSFS | Win95FS | DOS | ||
+ | +--------------+------------------+------------------+----------+----------+------------- | ||
+ | | ignore | NOT Owner W | NOT Owner W | Owner L | Owner L | -> ReadOnly | ||
+ | | ignore | Owner L | Owner L | 0 | 0 | -> Hidden | ||
+ | | ignore | Owner L | Owner L | 0 | 0 | -> System | ||
+ | | ignore | 0 | 0 | 0 | 0 | -> Volume | ||
+ | | ignore | ignore | ignore | ignore | ignore | -> Directory | ||
+ | | ignore | 0 | ignore | 0 | 0 | -> Archive | ||
+ | </div> | ||
+ | this can be done with the following code: | ||
+ | dosacc%=1-(acc% AND 2)/2 + (acc% AND 8)*0.75 :REM Sprow, LanManFS | ||
+ | dosacc%=8-(acc% AND 8)/8 :REM DOSFS, Win95FS | ||
+ | <!-- | ||
+ | RISC OS DOSFS translates file access permissions to DOS access permissions as | ||
follows<ref>From investigation with RISC OS 3.11</ref>: | follows<ref>From investigation with RISC OS 3.11</ref>: | ||
Line 202: | Line 240: | ||
this can be done with the following code: | this can be done with the following code: | ||
− | |||
dattr%=(attr% AND 8) DIV 8 | dattr%=(attr% AND 8) DIV 8 | ||
− | DOS access permissions are | + | RISC OS DOSFS translates DOS access permissions are translates as follows: |
1 -> Owner R | 1 -> Owner R | ||
Line 273: | Line 310: | ||
attr%=(((dattr% AND 6)<>0) AND 8) EOR (2*(dattr% AND 1)) OR 1 | attr%=(((dattr% AND 6)<>0) AND 8) EOR (2*(dattr% AND 1)) OR 1 | ||
+ | --> | ||
+ | |||
+ | ===CP/M=== | ||
+ | <div class="mw-widebody"> | ||
+ | | CPMFS | ZNOS | OSFILE | ||
+ | +--------------+--------------+------------- | ||
+ | | 1 | 1 | -> Owner R | ||
+ | | NOT ReadOnly | NOT ReadOnly | -> Owner W | ||
+ | | 0 | 0 | -> Owner E | ||
+ | | System | 0 | -> Owner L | ||
+ | | 1 | 1 | -> Public R | ||
+ | | NOT ReadOnly | 0 | -> Public W | ||
+ | | 0 | 0 | -> Public E | ||
+ | | 0 | 0 | -> Public L | ||
+ | this can be done with the following code: | ||
+ | acc%=&33-&22*(cpmacc% AND 1)+4*(cpmacc% AND 2):REM CPMFS | ||
+ | acc%=&13-&02*(cpmacc% AND 1) :REM ZNOS | ||
+ | |||
+ | | CPMFS | ZNOS | CP/M | ||
+ | +--------------+-------------+------------- | ||
+ | | NOT Owner W | NOT Owner W | -> ReadOnly | ||
+ | | Owner L | 0 | -> System | ||
+ | | ignore | 0 | -> Archive | ||
+ | | ignore | 0 | -> f1-f8 | ||
+ | this can be done with the following code: | ||
+ | cpmacc%=1-(acc% AND 2)/2+(acc% AND 8)/4:REM CPMFS | ||
+ | cpmacc%=1-(acc% AND 2)/2 :REM ZNOS | ||
+ | </div> | ||
===UNIX=== | ===UNIX=== | ||
+ | <div class="mw-widebody"> | ||
+ | | UnixFS<ref>TCP Protocol Suite User Guide</ref> | OSFILE | ||
+ | +------------------+----------------------------------- | ||
+ | | Owner r | -> Owner R | ||
+ | | Owner w | -> Owner W | ||
+ | | 0 | -> Owner E | ||
+ | | file: 0 | -> Owner L | ||
+ | | dir: NOT World E | -> Owner L | ||
+ | | World r | -> Public R | ||
+ | | World w | -> Public W | ||
+ | | 0 | -> Public E | ||
+ | | 0 | -> Public L | ||
+ | this can be done with the following code (probably easier with a lookup table): | ||
+ | acc%=0 | ||
+ | acc%=acc% OR (uxacc%AND01)*4 OR (uxacc%AND002)*1 OR (uxacc%AND004)/4 | ||
+ | acc%=acc% OR (uxacc%AND08)*8 OR (uxacc%AND016)*2 OR (uxacc%AND032)/2 | ||
+ | acc%=acc% OR (uxacc%AND64)*1 OR (uxacc%AND128)/4 OR (uxacc%AND256)/16 | ||
+ | |||
+ | | UnixFS file | UnixFS directory | Unix | ||
+ | +------------------------------+-------------------+--------------- | ||
+ | | (Owner R AND filetype=&FE6) | 1 | -> Owner x | ||
+ | | Owner W | unchanged | -> Owner w | ||
+ | | Owner R | unchanged | -> Owner r | ||
+ | | (Public R AND filetype=&FE6) | NOT Locked | -> Group x | ||
+ | | Public W | Public W | -> Group w | ||
+ | | Public R | Public R | -> Group r | ||
+ | | 0 | NOT Locked | -> World x | ||
+ | | Public W | Public W | -> World w | ||
+ | | Public R | Public R | -> World r | ||
+ | </div> | ||
+ | this can be done with the following code (probably easier with a lookup table): | ||
+ | uxacc%=0 | ||
+ | uxacc%=uxacc% OR (acc%AND01)*04 OR (acc%AND02)*1 OR (acc%AND04)/4 | ||
+ | uxacc%=uxacc% OR (acc%AND16)*02 OR (acc%AND32)/2 OR (acc%AND64)/8 | ||
+ | uxacc%=uxacc% OR (acc%AND16)*16 OR (acc%AND32)*4 OR (acc%AND64)*1 | ||
+ | IF type%=1:IF ftype%=&FE6:uxacc%=uxacc% OR (acc%AND01)*1 OR (acc%AND16)/2 | ||
+ | IF type%=2:uxacc%=((uxacc% AND &1B6) OR &49)-&48*(acc% AND 8) | ||
+ | |||
+ | <!-- | ||
BBC access permissions are translated to UNIX access permissions as | BBC access permissions are translated to UNIX access permissions as | ||
follows:<ref>TCP Protocol Suite User Guide</ref> | follows:<ref>TCP Protocol Suite User Guide</ref> | ||
Line 308: | Line 412: | ||
attr%=(uattr%AND1)*4+(uattr%AND2)+(uattr%AND4)DIV4+(uattr%AND8)*8+(uattr%AND16)*2+(uattr%AND32)DIV2 | attr%=(uattr%AND1)*4+(uattr%AND2)+(uattr%AND4)DIV4+(uattr%AND8)*8+(uattr%AND16)*2+(uattr%AND32)DIV2 | ||
attr%=attr% OR ((uattr%AND64)+(uattr%AND128)DIV4+(uattr%AND256)DIV16) | attr%=attr% OR ((uattr%AND64)+(uattr%AND128)DIV4+(uattr%AND256)DIV16) | ||
+ | |||
+ | --> | ||
==References== | ==References== |
Latest revision as of 17:15, 2 September 2024
Files have access attributes, returned and set in XY+14 in OSFILE calls. Each bit indicates different access rights to the file. However, care needs to be taken in interpreting these bits, particularly as errors have been propagated in most documentation on the matter.
Contents
Definition
Each access bit has the following definition:
b0 - R - file can be read by owner b1 - W - file can be written to by owner b2 - E - file can be executed by owner b3 - L - file cannot be deleted, renamed or overwritten by owner b4 - R - file can be read by public b5 - W - file can be written to by public b6 - E - file can be executed by public b7 - L - file cannot be deleted, renamed or overwritten by public
Note that lots of documentation (including the Advanced User Guides) list these as cannot be read or written. This is wrong. Each bit is set if the corresponding access right is present.
In access strings, the owner access is on the left of any '/' character, and the public access is on the right, sometimes in lower case. For example:
WR/R - owner read and write access, public read access only
The normal access string of WR/WR gives the access byte &33.
Read Access
Having read access means that a file can be read with LOAD, BGET, OSGBPB, *RUN and */.
The owner of a file can determine if they are allowed to read or load a file by examining the 'R' bit with:
readable%=(access% AND 1)<>0
Write Access
Having write access means that a file can be written to with BPUT and OSGBB. Not having write access does not mean that you cannot overwrite the file with SAVE. That is controlled by the Locked access.
The owner of a file can determine if they are allowed to write to a file by examining the 'W' bit with:
writable%=(access% AND 2)<>0
Execution Access
Having execute access means the file can be run with *RUN and */.
Most filing systems do not maintain a seperate execution access setting. If a file is readable, then it is also executable. Consequently, most filing systems either never return the 'E' bit, or always return the 'E' bit as a copy of the relevant 'R' bit.
The owner of a file can determine if they are allowed to run a file by examining both the 'R' and the 'E' bits with:
runnable%=(access% AND 5)<>0
If the 'E' bit is set and the 'R' bit is not set, then the file cannot be loaded or read, and can only be accessed with *RUN. The owner of a file can determine if a file is run-only with:
runonly%=(access% AND 5)=4
HADFS and HDFS maintain a seperate 'E' bit (HDFS calls it the 'X' bit). ADFS allows you to set 'E' access with the *ACCESS command to create a run-only file, but it does not reflect this in the returned file access byte. Also, ADFS does not let you set the 'E' bit with OSFILE, you can only do it with the *ACCESS command.
Locked Access
Being locked means that the file cannot be deleted, cannot be renamed, and cannot be overwritten with SAVE. Being locked does not mean the file cannot be written to with BPUT and OSGBPB. That is controlled by the Write access.
It may not be obvious, but a non-owner can never be able to delete a file. To a non-owner, a file is always locked, bit 7 is always implicitly set. However, most filing systems actually return bit 7 as an exact copy of bit 3, implying that a non-owner may be able to delete the file. You should never examine bit 7 to decide whether you can delete, rename or overwrite a file. If you do not own the file, you cannot delete it.
The owner of a file can determine if they are allowed to delete, rename or overwrite a file with:
deletable%=(access% AND 8)<>0
Owner vs Public
The access byte holds the owner's access in the bottom four bits and the public's access in the top four bits. However, there is no way of knowing whether you actually own the file you are examining and so which bits you should look at to determine your own access. OSGBPB 6 will tell you if you own the currently selected directory, but that does not have to be the directory that the file you are examining is in.
DFS
DFS must be considered as a special case, as it completely mangles the file access byte. Also, some DFS extensions or replacements have been written using the flawed documentation propagated by likes of the Advanced User Guide.
Reading the access byte
DFS only ever returns the 'Locked' bit in bit 3. It never returns anything for the owner 'R', 'W' or 'E' bits and never returns anything for the public access bits.
*ACCESS file returns an access byte of &00, ie: ---- *ACCESS file L returns an access byte of &08, ie: L---
Consequently, if reading the file access byte from DFS you must modify it before using it:
IF dfs% THEN access%=(access% OR 3)EOR(access% DIV 4) or IF dfs% THEN access%=access% DIV 4 * 3 + 3
This changes:
---- to --WR and L--- to L--R
Writing the access byte
Even though DFS only ever returns the owner's Locked bit, when writing the access byte both the Locked bit and the Write bit set the Locked bit.
Writing &00 (----) results in Unlocked Writing &02 (--W-) results in Locked Writing &08 (L---) results in Locked
Consequently, if writing the file access byte in DFS you must translate it before using it, and avoid writing to the 'W' bit:
IF dfs% THEN access%=access% AND 8
This changes all access bytes to just Locked off or Locked on.
HDFS
Hierarchial DFS by Andrew Duggan implements the full Locked, Execute, Write and Read access bits, but implements them according to the flawed documentation that says cannot read/etc instead of read/etc access present. Consequently, if reading or writing access bytes on HDFS, they must be translated:
IF FNhdfs THEN access%=(access% EOR 7)
HDFS and DFS both report themselves as filing system 4, but they use a different range of file handles. Calling FSCV with A=7 to request the handle range can be used to distinguish between them:
DEFFNhdfs A%=7:A%=USR !&21E =(A% AND &FF00)=&12
Note that this can only be done from the I/O processor.
Directories
Conventionally, the only access that directories can have is Locked or not Locked. If any other bit is written with OSFILE, they are either ignored entirely, or they are stored, but have no effect.
ADFS returns the 'R' bits set when reading a directory's access byte. RISC OS ADFS allows all the owner access bits to be set and read with OSFILE calls.
Some filing systems and programs[1] use the 'R' bit to indicate that the directory can be read - ie, catalogued - and the 'E' bit to indicate that the directory can be searched.
Private Access
HADFS and the SJ MDFS implement a 'P'rivate bit where an object is invisible to a non-owner. HADFS returns the 'P' bit in bit 7 of the access byte, whereas the NFS cannot see the MDFS's 'P' bit. On NFS bit 7 is a copy of the owner's Locked bit.
Unless copying within the same filing system, bit 7 should be ignored with:
access%=access% AND &7F
On RISC OS, the MDFS 'P' bit is returned in the owner's 'E' bit, and the 'P' bit is always returned set reflecting the fact that a non-owner can never delete an object.
Access permission on other systems
DOS
| | | | RISC OS | RISC OS | | Petrov DOSFS | Sprow DOSFS | LanManFS[2] | DOSFS[3] |Win95FS[4]| OSFILE +--------------+------------------+------------------+----------+----------+------------+ | 1 | 1 | 1 | 1 | 1 | -> Owner R | NOT ReadOnly | NOT ReadOnly | NOT ReadOnly | 1 | 1 | -> Owner W | 0 | 0 | 0 | 0 | 0 | -> Owner E | System | System OR Hidden | System OR Hidden | ReadOnly | ReadOnly | -> Owner L | 1 | 0 | 1 | 0 | 1 | -> Public R | NOT ReadOnly | 0 | NOT ReadOnly | 0 | 1 | -> Public W | 0 | 0 | 0 | 0 | 0 | -> Public E | 0 | 0 | 0 | 0 | 0 | -> Public L | | | | System | System | -> attr b8 | | | | Hidden | Hidden | -> attr b9 | | | | Archive | Archive | -> attr b10
this can be done with the following code:
acc%=&33-&22*(dosacc% AND 1)+2*(dosacc% AND 4) :REM Petrov acc%=&0B-&02*(dosacc% AND 1)-8*((dosacc% AND 6)=0) :REM Sprow acc%=&3B-&22*(dosacc% AND 1)-8*((dosacc% AND 6)=0) :REM LanManFS acc%=&0B-8*(dosacc% AND 1) :REM DOSFS acc%-&3B-8*(dosacc% AND 1) :REM Win95FS
| | | | RISC OS | RISC OS | | Petrov DOSFS | Sprow DOSFS | LanManFS | DOSFS | Win95FS | DOS +--------------+------------------+------------------+----------+----------+------------- | ignore | NOT Owner W | NOT Owner W | Owner L | Owner L | -> ReadOnly | ignore | Owner L | Owner L | 0 | 0 | -> Hidden | ignore | Owner L | Owner L | 0 | 0 | -> System | ignore | 0 | 0 | 0 | 0 | -> Volume | ignore | ignore | ignore | ignore | ignore | -> Directory | ignore | 0 | ignore | 0 | 0 | -> Archive
this can be done with the following code:
dosacc%=1-(acc% AND 2)/2 + (acc% AND 8)*0.75 :REM Sprow, LanManFS dosacc%=8-(acc% AND 8)/8 :REM DOSFS, Win95FS
CP/M
| CPMFS | ZNOS | OSFILE +--------------+--------------+------------- | 1 | 1 | -> Owner R | NOT ReadOnly | NOT ReadOnly | -> Owner W | 0 | 0 | -> Owner E | System | 0 | -> Owner L | 1 | 1 | -> Public R | NOT ReadOnly | 0 | -> Public W | 0 | 0 | -> Public E | 0 | 0 | -> Public L
this can be done with the following code:
acc%=&33-&22*(cpmacc% AND 1)+4*(cpmacc% AND 2):REM CPMFS acc%=&13-&02*(cpmacc% AND 1) :REM ZNOS
| CPMFS | ZNOS | CP/M +--------------+-------------+------------- | NOT Owner W | NOT Owner W | -> ReadOnly | Owner L | 0 | -> System | ignore | 0 | -> Archive | ignore | 0 | -> f1-f8
this can be done with the following code:
cpmacc%=1-(acc% AND 2)/2+(acc% AND 8)/4:REM CPMFS cpmacc%=1-(acc% AND 2)/2 :REM ZNOS
UNIX
| UnixFS[5] | OSFILE +------------------+----------------------------------- | Owner r | -> Owner R | Owner w | -> Owner W | 0 | -> Owner E | file: 0 | -> Owner L | dir: NOT World E | -> Owner L | World r | -> Public R | World w | -> Public W | 0 | -> Public E | 0 | -> Public L
this can be done with the following code (probably easier with a lookup table):
acc%=0 acc%=acc% OR (uxacc%AND01)*4 OR (uxacc%AND002)*1 OR (uxacc%AND004)/4 acc%=acc% OR (uxacc%AND08)*8 OR (uxacc%AND016)*2 OR (uxacc%AND032)/2 acc%=acc% OR (uxacc%AND64)*1 OR (uxacc%AND128)/4 OR (uxacc%AND256)/16
| UnixFS file | UnixFS directory | Unix +------------------------------+-------------------+--------------- | (Owner R AND filetype=&FE6) | 1 | -> Owner x | Owner W | unchanged | -> Owner w | Owner R | unchanged | -> Owner r | (Public R AND filetype=&FE6) | NOT Locked | -> Group x | Public W | Public W | -> Group w | Public R | Public R | -> Group r | 0 | NOT Locked | -> World x | Public W | Public W | -> World w | Public R | Public R | -> World r
this can be done with the following code (probably easier with a lookup table):
uxacc%=0 uxacc%=uxacc% OR (acc%AND01)*04 OR (acc%AND02)*1 OR (acc%AND04)/4 uxacc%=uxacc% OR (acc%AND16)*02 OR (acc%AND32)/2 OR (acc%AND64)/8 uxacc%=uxacc% OR (acc%AND16)*16 OR (acc%AND32)*4 OR (acc%AND64)*1 IF type%=1:IF ftype%=&FE6:uxacc%=uxacc% OR (acc%AND01)*1 OR (acc%AND16)/2 IF type%=2:uxacc%=((uxacc% AND &1B6) OR &49)-&48*(acc% AND 8)
References
Jgharston 23:57, 30 October 2011 (UTC)