>HADFS4 v5.77 A OSFILE - File/directory load/save/delete/create/information A =========================================================== (B This file is now too big to edit on a standard BBC or Master 2 < 07/06/1992, 4:30pm F# 20/11/1994: RunExec now in #2 P Solved find_blank problem Z" 26/08/1996: Rewritten OSFILE d/ 28/07/1998: Bugfix for =TIME$ on MOS 5.xx nG DiskMainLoop now with disk access code, path scanning now in here x) v5.52 Adding BigDir/BigDisk support 2 v5.53 Continuing with BigDir/BigDisk support _ Note: Cannot delete a file larger than 16M as ReturnToFSM can only deal with <16M lengths T To delete a 16M+ file, need to OPENUP it and reduce EXT in sub-16M steps T v5.61 Fixed delete (notfound), delete extended dirs, merge BigDisk FSM entries ? v5.62 Sets mtime on save, OSFILE &FC writes extended info F v5.66 ReadInfo($) uses offset to DIR, CDIR uses offset directory * v5.69 OSFILE &FC writes account info 8 v5.72 Save/restore shadow when loading final bytes G v5.75 Workaround for MOS5+NetFS RTC bug - drops out with an error E v5.77 MOS5+NetFS RTC bug bypassed by reading SoftRTC if on MOS5 :  "Assembling S.HADFS4" O%=P%-Block%+mcode%  [OPT0 :  .file "JSR GrabAbs:PHA:CLC:ADC #4 ,CMP #13:BCC file1:PLA:RTS 6 .file1 @"PHA:STX blk+0:STY blk+1:LDY #0 JLDA (blk),Y:STA &F2:INY TLDA (blk),Y:STA &F3:DEY ^CJSR SearchPathBad :\ Search for non-null filename h8TAY:PLA:ASL A:TAX :\ Y=file type 0/1/2 r@LDA fileTable+0,X:STA ws+0 :\ Index into dispatch table |LDA fileTable+1,X:STA ws+1 NPLA:JSR JumpWS :\ Call function with A=action, Y=filetype RTXA:LDX blk+0:LDY blk+1:RTS :\ Copy returned filetype in X to A and return : .fileTable EQUW fileFC EQUW fileFD:EQUW fileFE EQUW load :EQUW save EQUW file01:EQUW file02 EQUW file03:EQUW file04 EQUW file05:EQUW delete EQUW create:EQUW cdir : "\ On entry to OSFILE routines, \ A=function code \ Y=file type 0/1/2 \ sect=sector start &\ On exit, 0\ X=returned file type :: D: N .RdInf0 XPLA:LDA #0 b .fileFE l TAX:RTS v: '\ ================================= '\ Read and write object information '\ =================================  .file05 6A #&80 :\ Set b7=read info 3.fileFC:.fileFD:.file01:.file02:.file03:.file04 @PHA:TYA :\ Save A=action, Y=filetype 7JSR CheckDirInfo:BEQ RdInf0 :\ Object not found =BPL P%+5:JMP RdInf1 :\ b7=1, read info on '$' : 5PLA:BPL P%+5:JMP RdInf2 :\ Read file info BJSR CanISave:JSR AddB4 :\ Align blk and fptr pointers : @CMP #3:BCS SetExec :\ Skip setting load address  >PHA:LDY #5 :\ Point to load high byte DBIT HDR+&0C:BMI SetLoadLp :\ Large dir, set all four bytes  7LDA (blk),Y: #&3F:STA (blk),Y :\ Lose top two bits *BLDA (fptr),Y: #&C0:A (blk),Y:\ Merge with existing year bits 4>STA (fptr),Y:DEY :\ Store as load high byte >.SetLoadLp H;LDA (blk),Y:STA (fptr),Y :\ Copy to load address R DEY:CPY #1:BNE SetLoadLp:PLA \: f .SetExec p>LDY #9:PHA: #1:BEQ SetAttr :\ Skip setting exec address z.SetExecLp ;LDA (blk),Y:STA (fptr),Y :\ Copy to exec address DEY:CPY #5:BNE SetExecLp :  .SetAttr :JSR SubB4 :\ Restore blk pointer =PLA:PHA:CMP #1:BEQ SetAttrs :\ Jump to set attributes >CMP #4:BNE SetDone :\ Skip setting attributes :  .SetAttrs GLDY #&0E:LDA (blk),Y:JSR AccessByte:\ Set access from control block RLDY #&0F:JSR SetObjDate :\ Set modification date from control block :  .SetDone JSR SaveThisDir :  .RdInf1 $LPLA:A #&01 :\ Ensure fileFC('$') becomes fileFD('$') . .RdInf2 8>CMP #&FC:BNE RdInf2a :\ Not write extended info B;JSR CanISave:LDY #6 :\ CanISave changes A,Y LULDA HDR+&0C:BPL WrInf2 :\ SmallDir, no mtime,cdate, jump to set accounts VY\\LDY HDR+&0C:\\BPL ConvertBlk :\ SmallDir, no mtime,cdate, jump to set accounts `2\\JSR CanISave:\\LDY #6:\ CanISave changes A,Y j .WrInfLp t>LDA (blk),Y:STA Ctrl-2,Y :\ Copy mtime to workspace ~INY:CPY #9:BNE WrInfLp :JSR SetObjDate:JSR SetModTime :\ Set cdate and mtime JSR SaveThisDir  .WrInf2  LDX #1  .WrInf3 ODEY:LDA (blk),Y:STA numstore,X :\ Copy from from control block to numstore DEX:BPL P%+4:LDX #3 CPY #2:BNE WrInf3 6JSR RdInfType2 :\ Get object type BJMP SetAccounts :\ Jump to set account numbers \\LDA #&FC:\SEC :  .RdInf2a  FBCS ConvertBlk :\ A=&Fx, read/write extended info .ConvertBlk0 = #127 :\ b7=0, read standard info (.ConvertBlk 2BPHA:JSR AddB4:LDY #2 :\ Align blk and fptr pointers < .RdInfLp1 FJLDA (fptr),Y:STA (blk),Y:INY :\ Copy standard info to control block PCPY #17:BNE RdInfLp1 Z9LDA drive:STA (blk),Y:DEY :\ Store drive number d@LDA HDR+&0C: #&80:ASL A:PHP :\ Move BigDir flag into Carry nABCS RdInf3:STA (blk),Y :\ SmallDir sector is &00xxxx xCLDY #&0D:STA (blk),Y:DEY :\ SmallDir length is &000xxxxx  LDA (blk),Y: #7:STA (blk),Y LDY #5:LDA (blk),Y LDY #2:PLP:BEQ P%+4:INY:INY :\ Y=2 or 4 for acc or aux ;JSR StoreAX :\ Store account number JCPY #5:BEQ RdInfDir :\ Both numbers stored, jump to finish SPLP:PHP:LDY #&16:BCC RdInfAccLp :\ SmallDir auxilary account, jump back with NE QLDY #&0E:BNE RdInfAccLp :\ BigDir auxilary account, jump back with NE  .RdInfDir &KLDX #2:PLP:BMI RdInfDone :\ Get Dir flag back, return X=2 if dir 0HBPL RdInfType3 :\ File, jump to check run-only flag :: D\ Read standard info N\ ------------------ X .RdInfStd bPHP:LDY #7 l.ReadAccess v@LDA (fptr),Y:ROL A:ROL attrs :\ Read access from filename DEY:BPL ReadAccess LDA attrs: #&33 =LDY #&0E:STA (blk),Y :\ Store in control block : =LDY #md+1:PLP:JSR ReadInfoDate :\ Read modification date ALDY #&0F:JSR StoreAX :\ Store year+day, year+month 7INY:LDA #0:STA (blk),Y :\ Store final zero  ::\PHP : \.RdInfType  ::\PLP .RdInfType2 8LDY #8:LDA (fptr),Y:ASL A :\ Get Directory bit 0LDX #2:BCS RdInfDone :\ Directory  .RdInfType3 ;DEX:JSR YDoIOwn :\ Point to my Read bit  9LDA (fptr),Y:BPL RdInfDone :\ X=1, readable file *=INY:LDA (fptr),Y:BPL RdInfDone :\ X=1, not run-only file 4;LDX #&FF :\ X=&FF, run-only file >.RdInfDone H4RTS :\ X=object type R: \ .StoreAX f'STA (blk),Y:TXA:INY:STA (blk),Y:RTS p .FetchAX z)LDA (fptr),Y:TAX:DEY:LDA (fptr),Y:RTS : %\ ------------------------------- %\ Read object's modification date %\ ------------------------------- *\ On entry, (fptr),Y->top byte of date "\ CC = SmallDir '\ CS = BigDir or FSM \ On exit, A=year+day \ X=year+month )\ ----------------------------------- .ReadInfoDate BCC ReadDateSmall .ReadDateBig UJSR FetchAX:JMP Rotate5 :\ X=year+month, A=day+year, rotate to A=year+day : .ReadDateSmall $ALDY #&15:JSR FetchAX :\ X=year+month, A=day+length .0LSR A:LSR A:LSR A:STA attrs :\ Store day 8ALDY #&09:LDA (fptr),Y: #&80 :\ Get b4 of year from filename B0LSR A:LSR A:A attrs:STA attrs :\ Add to day LELDY #&0D:LDA (fptr),Y: #&C0 :\ b6-b5 of year from b7-b6 of load V0A attrs:RTS :\ A=year+day `: j .AddB4 t(PHA:LDA #8:CLC:ADC fptr+0:STA fptr+0 ~ LDA #0:ADC fptr+1:STA fptr+1 PLA:RTS .SubB4 (PHA:LDA fptr+0:SEC:SBC #8:STA fptr+0 (LDA fptr+1:SBC #0:STA fptr+1:PLA:RTS : K\ --------------------------------------------------------------------- K\ CheckDirInfo - Resolve unresolved directory or create fake root entry >\ Called by OSFILE to read info, and by OPEN to allow "$" K\ --------------------------------------------------------------------- "\ On entry, A= file type 0/1/2 \ sect= sector \ fptr=>file info or *\ &FFxx if unresolved dir. 0\ On exit, A=file type 0/1/2/&82, flags set (\ If A=&82, root info created 0\ ------------------------------------------ (.CheckDirInfo 2CJSR CheckForDir:BPL CheckDirEnd :\ Resolve unresolved directory LDA FSM+&18,X:STA (fptr),Y :\ Copy byte to info block ,GINX:CPX #8:BNE CheckDirLp2 :\ A now holds DiskFlags from &18+7 6ASL A:BCC CheckDirSmall @ALDY #&10:LDA (fptr),Y :\ Adjust LargeDisk disk size JLDY #&0D:STA (fptr),Y T.CheckDirSmall ^LDY #cd+0:LDA (fptr),Y h8PHA:INY:LDA (fptr),Y :\ Get creation date rLDY #md+1:STA (fptr),Y |@PLA:DEY:STA (fptr),Y :\ Copy to modification date start sector X\ ------------------------- b .delete l8TYA:JSR CheckForDir:BMI errLocked:\ Can't delete '$' v=TAX:BEQ DeleteNone :\ A=0, nothing to delete BJSR CheckNoWildcards :\ Can't delete with wildcards JSR CheckLocked >JSR ConvertBlk0 :\ Read object information LDY #&0E :\ Offset to SmallDir LINK L.DeleteLp3 V0LDA HDR+&00,Y:PHA :\ Push LINK `9LDA CURR,X:STA start,X :\ Copy CURR to start jMINY:DEX:BPL DeleteLp3 :\ SmallDir will have a dummy byte pushed t: ~.DeleteLp4 HJSR GetDir:JSR GetLINK :\ Get next chunk and it's LINK (LDA sect+2:CMP start+2:BNE DeleteLp4 (LDA sect+1:CMP start+1:BNE DeleteLp4 8LDA sect+0:CMP start+0:BNE DeleteLp4 :\ Follow LINKs : 0\ This chunk points to the one to be deleted 0\ ------------------------------------------ BLDX #3:LDY #&1A :\ Point to top of BigDir LINK ABIT HDR+&0C:BMI DeleteLp5 :\ Jump to pop LINK if BigDir APLA:DEX:LDY #&0F :\ Pop a SmallDir 2-byte LINK .DeleteLp5 HPLA:STA HDR+&00,Y :\ Pop LINK to previous chunk's LINK DEY:DEX:BNE DeleteLp5  : @JSR C8to300:PLP:BCC DeleteFSM :\ CLC=FSM already in memory 8JSR CheckHadfsDiskX :\ Trashes addr,sect (.DeleteFSM 2?JSR AddToFSM:CLC:PHP :\ Return this chunk to FSM <: F2\ Any empty directory chunks have been removed P2\ -------------------------------------------- Z.DeleteNoLink dEPLP:BCS DeleteNoFSM:JSR SaveFSM :\ Save FSM if called from Delete n.DeleteNoFSM xQJSR SaveThisDir:PLA:TAX:RTS :\ Save this directory and exit, A=X=filetype : : -\ --------------------------------------- -\ Check if current directory is @, % or & -\ ---------------------------------------  .CheckCLU LDX #0:LDY #0  .ChkCLULp 'LDA CSD+0,X:CMP sect+0:BNE ChkCLUOk 'LDA CSD+1,X:CMP sect+1:BNE ChkCLUOk 'LDA CSD+2,X:CMP sect+2:BNE ChkCLUOk 'LDA CSD+d,X:CMP drive:BEQ ChkCLUErr  .ChkCLUOk ,INX:INX:INX:INX:INY:CPX #12:BNE ChkCLULp RTS .ChkCLUErr "!LDA CSDinfo,Y:STA &101:LDY #4 ,.ChkCLULp2 6LDA CSDtxt,X:STA &10D,Y @!INX:DEY:BNE ChkCLULp2:LDY #12 J.ChkCLULp3 T!LDA CantDelete-1,Y:STA &101,Y ^DEY:BNE ChkCLULp3 hSTY &112:STY &100:JMP &100 r .CSDinfo |EQUB 150:EQUB 151:EQUB 162  .CSDtxt EQUS "DSC BIL DRU " .CantDelete EQUS "Can't delete" : : /\ ----------------------------------------- /\ Delete this entry from the Free Space Map /\ ----------------------------------------- ;\ On exit, FSM loaded and updated, fptr points to entry \ .DeleteThisEntry PHA D.z%:LDY #3:]:1:z%=P%-z%:P%=P%-z%:O%=O%-z% : 32-bit file length D.z%:LDY #2:]:0:z%=P%-z%:P%=P%-z%:O%=O%-z% : 24-bit file length .DeleteThisLp1 &7LDA len,Y:PHA:DEY:BPL DeleteThisLp1 :\ Save length 0=SEC:JSR GetLength :\ Get object length :CJSR GetSectAddr:JSR SectToStart :\ Get object start sector D=JSR CheckHadfsDiskX :\ Trashes addr,sect NHJSR AddToFSM:LDY #0 :\ Return this start/len to FSM X.DeleteThisLp2 b:PLA:STA len,Y:INY :\ Restore length lD.z%:CPY #4:]:1:z%=P%-z%:P%=P%-z%:O%=O%-z% : 32-bit file length vD.z%:CPY #3:]:0:z%=P%-z%:P%=P%-z%:O%=O%-z% : 24-bit file length BNE DeleteThisLp2 .CanISaveOk PLA .GetLenOk3 RTS : : /\ ----------------------------------------- /\ Get object length to len in whole sectors /\ ----------------------------------------- -\ CLC=Absolute length, SEC=Rounded length \ .GetLength PHP:LDY #&12  .GetLenLp 9LDA (fptr),Y:STA len-&12,Y:INY :\ Copy length to len  F.z%:CPY #&16:]:1:z%=P%-z%:P%=P%-z%:O%=O%-z% : 32-bit file length *F.z%:CPY #&15:]:0:z%=P%-z%:P%=P%-z%:O%=O%-z% : 24-bit file length 4BNE GetLenLp >=PLP:BIT HDR+&0C:PHP:BMI GetLenOk1 :\ Continue with BigDir H16M files : .GetLenRound JLDA len+0:BEQ GetLenOk2 :\ Round up to whole number of sectors FINC len+1:BNE GetLenOk2 :\ Note, don't need to worry about MINC len+2 :\ overflow from top byte, as impossible J :\ to have a &1000000-length file, as 9 :\ '$' is at &47-&4A ^.z%:BNE GetLenOk2:INC len+3:]:1:z%=P%-z%:P%=P%-z%:O%=O%-z% : 32-bit file length top byte .GetLenOk2 RTS :  .CanISave HPHA:JSR DoIOwn:BEQ CanISaveOk :\ If don't own dir, drop into error : .errNoAccess $6JSR errors:EQUB 189:EQUS "Insufficient access":BRK ..errNotFile 85JSR file_errors:EQUB 181:EQUS "is not a file":BRK B.errRunOnly L4JSR errors:EQUB 189:EQUS "File execute only":BRK V: `: j\ ====================== t\ Load and Save routines ~\ ====================== : \ ----------- \ Load a file \ ----------- \ On entry, A=&FF \ Y=0/1/2 \ sect=>start sector \ -------------------------  .load &CPY #1:BEQ LoadFile:BCS errNotFile JMP errNotFound  .LoadFile BLDA #&80:JSR CheckNotOpen :\ Ensure not open for writing  :JSR YDoIOwn :\ Point to my 'R' bit @LDA (fptr),Y:BPL LoadFile1 :\ 'R' bit present, can load :INY:INY:LDA (fptr),Y :\ Point to my 'E' bit (KBMI errRunOnly:BPL errNoAccess :\ No 'R' bit, either RunOnly or NoRead 2: <.LoadFile1 F LDY #2 P.LoadFileLp1 ZKLDA (blk),Y:STA addr-2,Y :\ Copy load address from control block dINY:CPY #6:BNE LoadFileLp1 n7LDA (blk),Y:BEQ LoadStart :\ load "file",addr x\ *\ load "file" - use file's own address \ Enter here from * *\ ------------------------------------ .UseFileAddr  LDY #10 .LoadFileLp2 ?LDA (fptr),Y:STA addr-10,Y :\ Copy file's load address INY:CPY #14:BNE LoadFileLp2 CJSR LoadHighByte:STA addr+3 :\ Expand SmallDir load address .LoadStart MCLC:JSR GetLength:JSR SectToStart :\ Get file length, start sector KLDX blk+1:INX:BEQ P%+5:JSR ConvertBlk0 :\ Fill control block for load _LDA #0:STA action:JSR DiskMain :\ Load data from disk, allowed to corrupt A,X,Y,P \ G\ DiskMain Calls CheckAddr, ScreenOn, ScreenOff, updates addr, sect \ "GLDA len+0:BEQ LoadFinish :\ No final sector to load ,GLDA shadow:LDX #4 :\ Get shadow flag to save 6.LoadFileLp3 @OPHA:LDA addr-1,X:DEX:BPL LoadFileLp3 :\ Save shadow and current address JHJSR GetToFSM:LDX #&FC :\ Load final sector to FSM T.LoadFileLp4 ^?PLA:STA addr+4,X:INX:BNE LoadFileLp4 :\ Restore address hCPLA:STA shadow :\ Restore shadow flag r: |9\ Enter here for OSGBPB 5..12 and loading last sector 9\ ---------------------------------------------------  .LoadGbPb  .LoadCont JBIT &27A:BMI LoadToTube :\ Tube present, is is Tube load? .LoadToHost ]JSR ScreenOn:LDY #0 :\ Select screen if needed, A,X,X,P may be corrupted .LoadHostLp ?LDA FSM,Y:STA (addr),Y :\ Copy data to memory  INY:CPY len+0:BNE LoadHostLp _JSR ScreenOff :\ Deselect screen if needed, A,X,X,P may be corrupted .LoadFinish DLDX #1:RTS :\ Return object=&01 - file .LoadToTube JLDY addr+3:INY:BEQ LoadToHost :\ Addr is &FFxxxxxx, load to I/O JSR TubeClaimLoad:LDY #0 .LoadTubeLp &=LDA FSM,Y:STA &FEE5:INY :\ Copy data to Tube 0GJSR TubeWait :\ 24us delay, total 30us/byte :CPY len+0:BNE LoadTubeLp DDJSR TubeRelease:LDX #1:RTS :\ Return object=&01 - file N: X: b.errExists l.JSR errors:EQUB 196:EQUS "File exists":BRK v: \ ----------- \ Save a file \ ----------- \ On entry, A=&FF \ Y=0/1/2 0\ sect=>start sector if existing file 0\ ------------------------------------------  .save 7JSR create :\ Create the entry aLDA #&FF:STA action:JSR DiskMain:\ Save the data, also check addr, allowed to corrupt A,X,Y,P ?LDX #1:RTS :\ Return object=&01 - file : : \ -------------  \ Create a file \ -------------  \ On entry, A=&FF *\ Y=0/1/2 40\ sect=>start sector if existing file >0\ ------------------------------------------ H .create R4TYA:TAX:LDY #10 :\ X=object type \ .MakeLp1 fNLDA (blk),Y:STA addr-10,Y:PHA :\ Copy start address to addr and stack it pINY:CPY #&E:BNE MakeLp1 z8SEC:LDA (blk),Y:SBC addr+0:STA len+0:\ len=end-start (INY:LDA (blk),Y:SBC addr+1:STA len+1 (INY:LDA (blk),Y:SBC addr+2:STA len+2 INY:LDA (blk),Y:SBC addr+3 =BNE errTooLong :\ Length>=16M - too long =BIT HDR+&0C:BMI CreateLenOk :\ BigDir, length>512M ok >LDA len+2:CMP #8:BCC CreateLenOk:\ SmallDir, length<512 ok : D\ -------------------------------------------------------------- \ errTooLong D\ trying to store 24-bit length in 19-bit SmallDir length field D\ trying to store 24-bit sector in 16-bit SmallDir sector field D\ -------------------------------------------------------------- .errTooLong 4JSR errorDIR:EQUB 198:EQUS "Length too long":BRK : .CreateLenOk $MJSR CheckPath:JSR CheckNoWildcards:\ Check no missing leafs, no wildcards .LTXA:CMP #2:BEQ errExists :\ Error if saving on top of a directory 8aTAY:BEQ CreateEntry2 :\ No existing file, create a new one, CC/PL/EQ=save new file BJSR CheckLocked LKJSR DeleteThisEntry :\ Loads FSM & remove entry at sect/len V\CLC:LDA #1:BNE CreateGo :\ Jump to create file, CC/PL/NE=save over existing file `\ j\ Create an entry t\ --------------- ~\ Called by CDIR, ǚ & &\ On entry, CC/PL/EQ=save new file )\ CC/MI =openout new file "\ CS =directory *\ ------------------------------------ .CreateEntry GPHA:PHA:PHA:PHA :\ Push dummy addr to balance stack .CreateEntry2 IPHP:JSR CanISave :\ Check I can save in this directory MJSR FindBlankEntry:LDY #17:LDA #0:\ Find space in directory, trashes addr .CreateLp2 ASTA (fptr),Y:DEY:BPL CreateLp2 :\ Blank out name & addresses BINC HDR+&0C :\ Increment number of entries OJSR CheckHadfsDiskX:PLP :\ Load Free Space Map (trashes sect, addr)  \ @\ Continue here when overwriting existing entry or new entry @\ ---------------------------------------------------------- (!\ On entry, (fptr) => entry 20\ (blk) => OSFILE control block <"\ len = length F3\ CC/PL/NE = save over existing file P)\ CC/PL/EQ = save new file Z(\ CC/MI = openout file d%\ CS = directory n3\ --------------------------------------------- x .CreateGo HPHP:JSR PutInName:LDY #18 :\ Put new name into directory entry .CreateLenLp ;LDA len-18,Y:STA (fptr),Y :\ Copy length to entry INY:CPY #21:BNE CreateLenLp ?LDA #0:STA (fptr),Y :\ Clear top byte of length DJSR GetLenRound :\ Round length to whole sectors 8JSR FindFreeSpace :\ Find space in FSM .z% F LDY #24:BIT HDR+&0C:BMI CreateLp1 :\ BigDir can fit 24-bit sector K DEY:LDA start+2:BEQ CreateLp1 :\ SmallDir can only fit 16-bit sector [ \JSR ClearDIR:JMP errTooLong :\ Invalidate DIR, can't fit 24-bit sector in SmallDir  .CreateLp1 F LDA start-22,Y:STA (fptr),Y :\ Copy sector to directory entry  DEY:CPY #21:BNE CreateLp1 0:]: base$>=5.78:z%=P%-z%:P%=P%-z%:O%=O%-z% .z% " JSR CreatePutSector ,/:]: base$<5.78:z%=P%-z%:P%=P%-z%:O%=O%-z% 6 LDY #9 @>LDA #&FF:PLP:PHP:BCC CreateFile :\ CC=set address for file J6DEY:JSR SetB7:LDY #3:JSR SetB7 :\ Set 'D' and 'L' TBMI CreateDate ^.CreateFile hBPL CreateNotOpen r.CreateOpen |CINY:STA (fptr),Y :\ Set load & exec to &FFFFFFFF )CPY #17:BNE CreateOpen:BEQ CreateDate .CreateNotOpen 9JSR AddB4 :\ Align fptr and blk .CreateLp2 QLDA (blk),Y:STA (fptr),Y :\ Copy addresses from control block to entry 5DEY:CPY #1:BNE CreateLp2:JSR SubB4:\ Restore fptr .CreateDate DJSR SetCrDate:BCC CreatePutEntry:\ Set entry's modification date : 0JSR SetModTime :\ Set mtime MPLP:PHP:BNE CreatePutEntry :\ Skip past if saving over existing file =LDY #md-1:LDA #0:STA (fptr),Y :\ Set spare byte to zero DINY:LDA (fptr),Y:PHA :\ New file, copy mdate to cdate INY:LDA (fptr),Y LDY #cd+1:STA (fptr),Y PLA:DEY:STA (fptr),Y &: 0.CreatePutEntry :LPLP:JSR SaveFSM:JSR SaveThisDir :\ Balance stack, save FSM and directory D LDX #3 N.CreateLp4 X3PLA:STA addr,X:DEX :\ Restore addr b?BPL CreateLp4:LDX #1:RTS :\ Return object=&01 - file l: v.z% .CreatePutSector FLDY #24:BIT HDR+&0C:BMI CrPutSecLp :\ BigDir can fit 24-bit sector MDEY:LDA start+2:BEQ CrPutSecLp :\ SmallDir can only fit 16-bit sector ]JMP errTooLong :\ Invalidate DIR, can't fit 24-bit sector in SmallDir .CrPutSecLp HLDA start-22,Y:STA (fptr),Y :\ Copy sector to directory entry "DEY:CPY #21:BNE CrPutSecLp:RTS /:]: base$<5.78:z%=P%-z%:P%=P%-z%:O%=O%-z% :  .C8to16K 6LDA #&40:STA len+1 :\ Set len=&0040xx LDA #0:BEQ C8to00  .C8to300 6LDA #3:STA len+1 :\ Set len=&000300  \.C8to000 6LDA #0:STA len+0 :\ Set len=&00xx00  .C8to00 *6STA len+2:RTS :\ Set len=&00xxxx 4: >.ZeroNumber HLDA HDR+&0C R .ZeroNumA \ #&E0:STA HDR+&0C:RTS f: p: z\ ------------------ \ Create a directory \ ------------------  .cdir ECPY #2:BEQ CDirExit :\ Directory already exists, exit _TYA:BEQ P%+5:JMP errExists :\ File exists - error, nothing exists - create a directory \JSR C8to300:SEC:JSR CreateEntry :\ CS=dir, create &300-byte entry, start=>sector to save MJSR GetFIRSTorCURR :\ If FIRST<>0, sect=FIRST else sect=CURR GJSR dirInit:JSR PutInName :\ fptr=>DIR, put in directory name NJSR ZeroNumber:ASL A :\ Clear number of entries, Cy=BigDir flag SLDX #1:LDY #&0B:BCC CDirLp1 :\ SmallDir - X=2 byte sector, Y=>2-byte Parent SINX:LDY #&1E :\ BigDir - X=3 byte sector, Y=>3-byte Parent  .CDirLp1 DLDA sect,X:STA HDR+&00,Y :\ Parent=previous FIRST or CURR DEY:DEX:BPL CDirLp1 LINK+1 $OLDX #8:LDY #&1B :\ BigDir - X=8 bytes to clear, Y=>LINK+3 . .CDirLp2 8=STA HDR,Y :\ Clear a byte of header BBBCS P%+5:STA HDR+6,Y :\ SmallDir - also clear FIRST LDEY:DEX:BPL CDirLp2 V2STA HDR+&0D :\ Clear Cycle `JSR StartToSect:JSR PutDir :\ Save this new directory tJSR ClearDIR ~ .CDirExit RLDX #2:RTS :\ Clear buffer, return object=&02 - directory :  .SetB7 %LDA (fptr),Y:A #128:STA (fptr),Y RTS : .PutInName LDY #9:.PutNameLp LDA (fptr),Y:ASL A:PHP LDA OBJECT,Y:ASL A:PLP ROR A:STA (fptr),Y DEY:BPL PutNameLp RTS  : : \ --------------------- (\ Set Modification date 2\ --------------------- <'\ On entry, fptr=>file entry or FSM F:\ If FSM, needs CLC = small directory or FSM P8\ SEC = big directory or FSM Z,\ On exit, CLC = small directory or FSM d*\ SEC = big directory or FSM n'\ addr/tmp can be trashed x:\ ---------------------------------------------------- .SetCrDate CLDA HDR+&0C:ASL A :\ Get BigDir flag to Carry .SetCrDateFSM : @\ Bug in MOS 5.xx - If MOS5 + NetFS + FSTime - forces NetFS, 0\ corrupts &C0-&CB, &C1xx, maybe some others >PHP :\ Save Small/Big flag : .z% >LDA #0:STA Ctrl+2:STA Ctrl+1 :\ Clear control block 8LDX #1:JSR OSBYTE:CPX #5 :\ CC=NotCompact #LDX #Ctrl 255:LDY #Ctrl 256 @LDA #1:BCC SetCrDateOsw :\ Not Compact, call MOS CSTX &F0:STY &F1:JSR Osw14RTC :\ Compact, avoid NetFS bug $BEQ SetCrDate2:BEQ SetCrDateNone .SetCrDateOsw "=STA Ctrl:LDA #14:JSR OSWORD :\ Read BCD Time&Date ,/:]:1:z%=P%-z%:P%=P%-z%:O%=O%-z%: 34 bytes 6: @.z% J>LDX #0:STX Ctrl+2:STX Ctrl+1 :\ Clear control block TINX:STX Ctrl ^LDX &DD7:LDA &2A1,X:PHA hfile entry or adjusted for FSM entry !.\ A = year+month, to be stored ! C\ X = year+day, to be rotated or split across bytes !*C\ ------------------------------------------------------------- !4.SetModDate !>FBCC SetModDateSmall :\ Set date in small directory !HCPY #&0F:LDY #cd+1:BCC P%+4 !R;LDY #md+1:STA (fptr),Y:TXA :\ Store year+month !\PJSR Rotate3:DEY:STA (fptr),Y:SEC:RTS:\ Rotate year+day to day+year and store !f.SetModDateSmall !p;LDY #&15:STA (fptr),Y :\ Store year+month !z@ :\ This can be optimised !TLDY #&0D:LDA #&3F: (fptr),Y:STA (fptr),Y:\ Drop top year bits from load address !TTXA: #&C0:A (fptr),Y:STA (fptr),Y :\ Put new top year bits in load address !LTXA:ASL A:ASL A:ASL A:PHA:PHP :\ Move year bit 5 into Carry !QLDY #&09:LDA (fptr),Y:ASL A:PLP:ROR A :\ Move year bit 5 into name bit 7 !STA (fptr),Y !KLDY #&14:LDA #7: (fptr),Y:STA (fptr),Y :\ Drop top 5 bits from length !MPLA:A (fptr),Y:STA (fptr),Y:CLC:RTS :\ Put day into length top bits !: !\.SetCrDate0 !(\LDA #0:\STA Ctrl+2:\STA Ctrl+1:\RTS !: !.Rotate5:CMP #&80:ROL A !.Rotate4:CMP #&80:ROL A ".Rotate3:CMP #&80:ROL A "*.Rotate2:CMP #&80:ROL A:CMP #&80:ROL A "RTS "$: "./\ ----------------------------------------- "8/\ SetModTime - Set object modification time "B/\ ----------------------------------------- "L#\ On entry, fptr =>file entry "V\ Ctrl+4 = hours "` \ Ctrl+5 = minutes "j \ Ctrl+6 = seconds "t/\ ----------------------------------------- "~.SetModTime ""LDA Ctrl+5:ASL A:ASL A:STA tmp "LDA Ctrl+4:ASL tmp:ROL A "ASL tmp:ROL A:ASL tmp:ROL A "LDY #mt+1:STA (fptr),Y "LDA Ctrl+6:LSR A:A tmp "DEY:STA (fptr),Y:RTS ": ": "1\ ------------------------------------------- "1\ Look for a blank entry in current directory "1\ ------------------------------------------- "#\ On exit, NE = directory full # \ EQ = entry found # $\ fptr=>directory entry #$\ ------------------------------ #.FindBlankLook #(3JSR dirInit :\ Y=0, A=files #24CMP #31:BEQ FindBlankFull :\ SmallDir full #<BIT HDR+&0C:BPL FindBlankLp #F2CMP #23:BCS FindBlankFull :\ BigDir full #P.FindBlankLp #ZWJSR dirNext:BEQ FindBlankOk :\ This entry empty, exit with fptr=>entry, A=0, EQ #dWLDA files:BEQ FindBlankOk :\ End of directory, exit with fptr=>entry, A=0, EQ #n?DEC files:BPL FindBlankLp :\ Loop through all entries #x.FindBlankFull # LDA #&FF #.FindBlankOk #RTS #: #$\ ------------------------------ #$\ Create a blank directory entry #$\ Extend directory if neccessary #$\ ------------------------------ #$\ On exit, fptr=>directory entry # \ A,X,Y,P corrupted #$\ ------------------------------ #.FindBlankEntry #?JSR FindBlankLook:BEQ FindBlankOk :\ Found in current chunk $MJSR GetFIRST:BEQ FindExtend :\ No multiple chunks, extend directory $.FindBlankLp2 $:JSR GetDir :\ Get current chunk $">JSR FindBlankLook:BEQ FindBlankOk :\ Look in current chunk $,KJSR GetLINK:BNE FindBlankLp2 :\ No empty entries, check next chunk $6: $@\ Try to extend directory $J\ ----------------------- $T.FindExtend $^ LDX #2 $h .FindExt1 $r1LDA len,X:PHA:DEX:BPL FindExt1 :\ Save len $|?JSR CheckHadfsDiskX:JSR C8to300 :\ Load FSM, set len=&300 $HJSR FindFreeSpace :\ start=space for directory chunk $;LDA sect+2:BEQ FindExt2 :\ sect<16M, continue $9LDA HDR+&0C:BMI FindExt2 :\ BigDir, continue $GJMP errTooLong :\ sect>16M won't fit in SmallDir $ .FindExt2 $EJSR SaveFSM:JSR GetFIRST:PHA :\ Save FSM, stack 0 if FIRST=0 $;JSR GetFIRSTorCURR :\ sect=FIRST or CURR $ALDA HDR+&0C:ASL A:PHP :\ Get BigDir flag to Carry $ALDX #2:BCC FindExt4 :\ BigDir X=2, SmallDir X=1 $ .FindExt3 $CLDA sect,X:STA HDR+&14,X :\ FIRST=FIRST for all chunks $.FindExt4:DEX:BPL FindExt3 $ALDA HDR+&0C:PHA:JSR ZeroNumber :\ Zero number in new chunk %0 %&ALDX #3:BCC FindExt8 :\ BigDir X=3, SmallDir X=1 %0 .FindExt7 %:STA HDR+&14,X %DC.FindExt8:DEX:BPL FindExt7 :\ Clear FIRST in first chunk %N .FindExt9 %XZJSR StartToSect:LDX #2:LDY #&1A :\ Get sect of new chunk from start, Y=BigDir LINK+2 %bPLP:BCS FindExt10 %lKDEX:LDY #&0F:LDA #0:PHA :\ X=size of sect, Y=>SmallDir LINK+1 %v.FindExt10 %=LDA sect,X:STA HDR+&00,Y:PHA :\ Set LINK and save it %DEY:DEX:BPL FindExt10 %2JSR SaveThisDir:LDX #0 :\ Save CURR %.FindExt11 %BPLA:STA sect,X :\ Restore sect of new chunk %INX:CPX #3:BNE FindExt11 %6JSR GetDir:LDX #0 :\ Get new chunk %.FindExt12 %PLA:STA len,X %7INX:CPX #3:BNE FindExt12 :\ Restore length % .dirFirst %:JSR dirInit:JMP dirNext :\ fptr=>first entry %: & \ -------------------------- & \ Check OBJECT for wildcards & \ -------------------------- & \ On exit, X preserved &*\ -------------------- &4.CheckNoWildcards &>LDY #9:.ChckWldLp &H&LDA OBJECT,Y:CMP #"*":BEQ errWild &RCMP #"#":BEQ errWild &\DEY:BPL ChckWldLp:RTS &f .errWild &p,JSR errors:EQUB &FD:EQUS "Wildcards":BRK &z: &] &$ 11;20,9);O%-mcode%;" bytes" &>"S.HADFS5"