********************************************************************
* RBF - Random Block File Manager
*
* $Id$
*
* Modified for 6309 Native mode by Bill Nobel, L. Curtis Boyle & Wes Gale
*
* This also contains the patch for un-deleting files
*
* Undocumented SetStt/GetStt calls:
*
*     GetStt:
*         SS.FD ($0F) - Returns a file descriptor
*                          Entry: R$A=Path #
*                                 R$B=SS.FD ($0F)
*                                 R$X=Pointer to a 256 byte buffer
*                                 R$Y=# bytes of FD required
*         SS.FDInf ($20) - Directly reads a file descriptor from anywhere
*                          on drive.
*                          Entry: R$A=Path #
*                                 R$B=SS.FDInf ($20)
*                                 R$X=Pointer to a 256 byte buffer
*                                 R$Y= MSB - Length of read
*                                      LSB - MSB of logical sector #
*                                 R$U= LSW of logical sector #
*     SetStt:
*         SS.FD ($0F) - Writes a file descriptor
*                          Entry: R$A=Path #
*                                 R$B=SS.FD ($0F)
*                                 R$X=Pointer to a maximum 256 byte buffer
*                                 R$Y=# bytes of FD to write
*         SS.Ticks ($10) - Set # ticks to wait for record lock release
*                          Entry: R$A=Path #
*                                 R$B=SS.Ticks ($10)
*                                 R$X=# Ticks to wait
*         SS.Lock ($11) - Force Lock/Release of a file.
*                         Locks from current position to a specified size
*                          Entry: R$A=Path #
*                                 R$B=SS.Lock ($11)
*                                 R$X=LSW of end byte position
*                                 R$U=MSW of end byte position
*         SS.Attr ($1C) - Allows changing of file/directory attributes
*                         If changing directory attribute it scans to
*                         see if directory is empty.
*                          Entry: R$A=Path #
*                                 R$B=SS.Attr ($1C)
*                                 R$X= LSB - File attributes
*         SS.RsBit ($1E) - Reserve bitmap sector (doesn't allocate)
*                          Locks the bitmap sector from other programs
*                          so they cannot allocate in it.
*                          Useful when working in allocation map.
*                          Entry: R$A=Path #
*                                 R$B=SS.RsBit ($1E)
*                                 R$X= LSB - Sector # of bitmap
*
* Edt/Rev  YYYY/MM/DD  Modified by
* Comment
* ------------------------------------------------------------------
*          1993/09/19  ???
* Started putting in comments from buggy 1.09 code, fixed WP error
* bug on file delete, fixed FD read error bug in delete.
*
*          1994/07/15  ???
* Fixed long overdue LHA bug; modified M$Exec driver calls @ L11EB
* to use V$DRIVEX.
*
*          1994/07/27  ???
* Changed L11EB to just PSHS/PULS A,X,PC instead of D,X,PC (saves
* 2 cycles per driver call); changed BRA L12C6 @ L128E to PULS PC,U,X
*
*          ????/??/??  ???
* NitrOS-9 2.00 distribution.
*
*  35      ????/??/??  Gene Heskett
* Fixed FD.SEG bug.
*
*          2003/04/21  Boisy G. Pitre
* Folded RBF 30 comments into this version.
*
*  36      2003/05/01  Rodney V. Hamilton
* Fix for LSN0 DD.TOT=0 lockout problem
*
*  37      2004/06/18  Boisy G. Pitre
* Added call to driver's SS.VarSect GetStat in order to obtain the
* sector size of the media.
*
*  37r2    2004/07/18  Boisy G. Pitre
* RBF checks error code on return from SS.VarSect and only returns
* error if error code is != E$UnkSvc (fixes problems with drivers
* which do not support SS.VarSect and return E$UnkSvc in their GetStat
* routines after evaluating an unknown service code.)

         nam   RBF
         ttl   Random Block File Manager

         ifp1  
         use   defsfile
         endc  

rev      set   $02
ty       set   FlMgr
         IFNE  H6309
lg       set   Obj6309
         ELSE
lg       set   Objct
         ENDC
tylg     set   ty+lg
atrv     set   ReEnt+rev
edition  set   37

         org   $00
size     equ   .

         mod   eom,name,tylg,atrv,start,size

name     fcs   /RBF/
         fcb   edition

*L0012    fcb   DRVMEM


****************************
*
* Main entry point for RBF
*
* Entry: Y = Path descriptor pointer
*        U = Register stack pointer

start    bra   Create
         nop   
         lbra  Open
         lbra  MakDir
         lbra  ChgDir
         lbra  Delete
         lbra  Seek
         lbra  Read
         lbra  Write
         lbra  ReadLn
         lbra  WriteLn
         lbra  GetStat
         lbra  SetStat
         lbra  Close


*
* I$Create Entry Point
*
* Entry: A = access mode desired
*        B = file attributes
*        X = address of the pathlist
*
* Exit:  A = pathnum
*        X = last byte of pathlist address
*
* Error: CC Carry set
*        B = errcode
*
Create   
         pshs  y		Preserve path desc ptr
         leas  -$05,s		Make 5 byte buffer on stack
         IFNE  H6309
         aim   #^DIR.,R$B,u
         ELSE
         lda   R$B,u		force directory bit off
         anda  #^DIR.
         sta   R$B,u
         ENDC
         lbsr  FindFile		try & find it in directory
         bcs   Creat47		branch if doesn't exist

* File already exists
         ldb   #E$CEF		else exists error
Creat47  cmpb  #E$PNNF		not found?
         bne   Creat7E

* File doesn't exist, create it
         cmpa  #PDELIM		full path?
         beq   Creat7E		yes, return
         pshs  x		preserve filename pointer
         ldx   PD.RGS,y		get register stack pointer
         stu   R$X,x		save updated pathname pointer
* These 4 did have < in front, made 3 byte cmnds but some are 2!
         ldb   PD.SBP,y		get physical sector # of segment list
         ldx   PD.SBP+1,y
         lda   PD.SSZ,y		get size of segment list in bytes
         ldu   PD.SSZ+1,y
         pshs  u,x,b,a		preserve it all
         ldx   PD.RGS,y		get register stack pointer
* Calculate default file size, if enabled
* This sets D to 0 if bit 5 of R$A is NOT set.  If bit 5 of R$A is set
* when called, register Y will contain a default file size
         lda   R$A,x		get file mode (read/write/update)
         clrb  
         anda  #PEXEC.		bit 5 set?
         beq   Creat6E		no, skip ahead
         ldd   R$Y,x		get default file size
* account for FD sector, I think.
* changed from addd #1, bcc, ldd #$FFFF.
* The INCD gets D=$0000 (and CC.Z set) if it overflows from $FFFF->$0000
* then if it's zero, a DECD forces it to be $FFFF
Creat6E  addd  #1		above 64k in size? (bug fix, thanks Gene K.)
         bcc   Creat75		no, skip ahead: changed from BCC
         ldd   #$FFFF		force it to 64k
Creat75  lbsr  FatScan		find the space in the allocation map
         bcc   Creat83		got it, skip ahead
         leas  6,s		purge segment sizes from stack
* and fall through to routine which returns with an error.

Creat7C  leas  2,s		purge user's pathname pointer
Creat7E  leas  5,s		purge local data
         lbra  ErMemRtn		return with error

* Create the file
Creat83  std   $0B,s		save segment size
         ldb   PD.SBP,y		save segment physical sector # in path desc.
         ldx   PD.SBP+1,y	starting LSN
         stb   $08,s		on stack too
         stx   $09,s
         puls  u,x,b,a		restore segment physical sector # & sizes
         stb   PD.SBP,y		save it as current
         stx   PD.SBP+1,y
         sta   PD.SSZ,y
         stu   PD.SSZ+1,y
* Find empty slot in directory sector for new file
         IFNE  H6309
         ldq   PD.DCP,y		get directory entry pointer for new file
         stq   PD.CP,y		save it as current file pointer
         ELSE
         ldd   PD.DCP,y
         std   PD.CP,y
         ldd   PD.DCP+2,y
         std   PD.CP+2,y
         ENDC
         lbsr  L0957		move entry into sector buffer
         bcs   CreatB5
CreatAC  tst   ,x		file exist here already?
         beq   CreatC7		no, found empty slot, skip ahead
         lbsr  L0942		point to next entry
         bcc   CreatAC		try again
CreatB5  cmpb  #E$EOF		end of directory?
         bne   Creat7C		no, return error
* Create the directory entry for new file
         ldd   #DIR.SZ		get size of directory entry
         lbsr  Writ599		add it to size of directory
         bcs   Creat7C		out of alloc?
         lbsr  MDir263		set file size in file descriptor
         lbsr  L0957		read in a directory sector
CreatC7  leau  ,x		point to directory entry
         lbsr  Creat169		clear it out
         puls  x		restore pathname pointer
         os9   F$PrsNam		parse it to get filename
         bcs   Creat7E
         cmpb  #29		length of name right size?
         bls   CreatD9		yes, skip ahead
         ldb   #29		else force it to 29 chars
CreatD9  clra  			move length to Y
         tfr   d,y
         lbsr  Writ5CB		move name of file to directory entry
         tfr   y,d		move length of name to D
         ldy   $05,s		restore PDpointer
         decb  			subtract 1 off length
         IFNE  H6309
         oim   #$80,b,u		set high bit on last char of name
         ELSE
         lda   b,u
         ora   #$80
         sta   b,u
         ENDC
         ldb   ,s		get logical sector # of file desc
         ldx   $01,s
         stb   DIR.FD,u		save it into directory entry
         stx   DIR.FD+1,u
         lbsr  L1205		flush sector to disk
         bcs   Creat151
* Setup file descriptor
         ldu   PD.BUF,y		get sector buffer pointer
         bsr   Creat170		clear it out
         lda   #FDBUF		get file descriptor in buffer flag
         sta   PD.SMF,y		save it as current sector buffer state
         ldx   PD.RGS,y		get register stack pointer
         lda   R$B,x		get file attributes
         sta   FD.ATT,u		save it as current attributes
         ldx   <D.Proc		get process pointer
         ldd   P$User,x		get user #
         std   FD.OWN,u		save creation user
         lbsr  L02D1		place date & time into file descriptor
         ldd   FD.DAT,u		get date last modified
         std   FD.Creat,u	save it as creation date (since we just made it)
         ldb   FD.DAT+2,u
         stb   FD.Creat+2,u
         ldb   #$01		get link count
         stb   FD.LNK,u
         ldd   3,s		get segment size in sectors
         IFNE  H6309
         decd  			is it 1?
         ELSE
         subd  #$0001
         ENDC
         beq   Creat131		yes, skip ahead
         leax  FD.SEG,u		point to the start of the segment list
         std   FDSL.B,x		save segment size
         ldd   1,s		get LSW of physical sector # of seg start
         addd  #1		we need to carry below, fr the adcb! (bug fix, thanks Gene K.)
         std   FDSL.A+1,x	save LSW
         ldb   ,s		get MSB of physical sector # of segment start
         adcb  #$00		need carry status of addd above
         stb   FDSL.A,x		save MSB
Creat131 ldb   ,s		get p hysical sector # of segment start
         ldx   1,s
         lbsr  L1207		flush file descriptor to disk
         bcs   Creat151
         lbsr  L0A90		sort out any conflict for this sector
         stb   PD.FD,y		save file descriptor physical sector # to pd
         stx   PD.FD+1,y
         lbsr  L0A2A		update file/record lock for this sector
         leas  $05,s		purge sector buffer from stack
         IFGT  Level-1
         ldx   PD.Exten,y	get path extension pointer
         lda   #EofLock		set the file to EOF lock
         sta   PE.Lock,x
         ENDC
         lbra  Open1CC
* Error on FD write to disk
Creat151 puls  u,x,a		restore segment start & size
         sta   PD.SBP,y		put it into path descriptor
         stx   PD.SBP+1,y
         clr   PD.SSZ,y
         stu   PD.SSZ+1,y
         pshs  b		save error code
         lbsr  ClrFBits
         puls  b		restore error code
RtnMemry lbra  ErMemRtn		return with error

* Clear out directory entry
* Entry: U = Directory entry pointer
Creat169 
         IFNE  H6309
         ldw   #DIR.SZ		get size of directory entry (name & LSN of FD)
         ELSE
         ldb   #DIR.SZ
         ENDC
         bra   Creat174		clear it out

* Clear out sector buffer
* Entry: U = Sector buffer pointer
Creat170 
         IFNE  H6309
         ldw   #$0100		get size of sector buffer
         ELSE
         clrb
         ENDC
Creat174 pshs  u,x		preserve regs
         IFNE  H6309
         leax  <Creat170+3,pcr	point to NULL byte
         tfm   x,u+		clear buffer
         ELSE
l1       clr   ,u+
         decb
         bne   l1 
         ENDC
         puls  pc,u,x		restore & return


*
* I$Open Entry Point
*
* Entry: A = access mode desired
*        X = address of the pathlist
*
* Exit:  A = pathnum
*        X = last byte of pathlist address
*
* Error: CC Carry set
*        B = errcode
*
Open     
         pshs  y		preserve path descriptor pointer
         lbsr  FindFile		try & find the file in current directory
         bcs   RtnMemry		couldn't find it, return error
         ldu   PD.RGS,y		get register stack pointer
         stx   R$X,u		save updated pathname pointer
         ldd   PD.FD+1,y	do we have a file descriptor?
         bne   Open1BB
         lda   PD.FD,y
         bne   Open1BB		yes, skip ahead
* File descriptor doesn't exist
         ldb   PD.MOD,y		get current file mode
         andb  #DIR.		is it a directory?
         lbne  Clos29D		yes, return not accessible eror
         std   PD.SBP,y		set segment physical start to 0
         sta   PD.SBP+2,y
         std   PD.SBL,y		do logical as well
         sta   PD.SBL+2,y
         ldx   PD.DTB,y		get pointer to drive table
         lda   DD.TOT+2,x	get total # sectors on drive
* resave nonzero DD.TOT here and recopy
OpenFix  equ   *
         std   PD.SIZ+2,y	copy it to file size (B=0)
         sta   PD.SSZ+2,y	copy it to segment size as well
         ldd   DD.TOT,x
         std   PD.SIZ,y
         std   PD.SSZ,y
* BUG FIX: handle special case of DD.TOT=0 in LSN0 which blocks
* all subsequent accesses.  NOTE: since we can only access LSN0
* for any non-zero value, set DD.TOT=1 to avoid NOT READY error.
         bne   OpenRet		MSW nonzero, OK
         lda   DD.TOT+2,x	MSW=0, check LSB
         bne   OpenRet		LSB nonzero, OK
         inca			DD.TOT=0, make it 1
         sta   DD.TOT+2,x	fix drive table
         bra   OpenFix		and resave (B=0)
OpenRet  puls  pc,y		restore & return

Open1BB  lda   PD.MOD,y		get file mode
         lbsr  ChkAttrs		can user access file?
         bcs   RtnMemry		no, return no permission error
         bita  #WRITE.		open for write?
         beq   Open1CC		no, skip ahead
         lbsr  L02D1		update last date modified to current
         lbsr  L11FD		update file descriptor on disk
Open1CC  puls  y		restore path descriptor pointer

* Update the path descriptor from the FD sector pointed to by U
Open1CE  
         IFNE  H6309
         clrd  			get a 16 bit zero value
         ELSE
         clra  
         clrb  
         ENDC
         std   PD.CP+2,y	set seek pointer to start of file
         std   PD.CP,y
         std   PD.SBL,y		set segment start
         sta   PD.SBL+2,y
         sta   PD.SSZ,y		set segment size
         lda   FD.ATT,u		get file attributes
         sta   PD.ATT,y		put it into path descriptor
         ldd   FD.SEG,u		get the file's segment start sector #
         std   PD.SBP,y
         lda   FD.SEG+2,u
         sta   PD.SBP+2,y
         ldd   FD.SEG+FDSL.B,u
         std   PD.SSZ+1,y
* ldq   FD.SIZ,u
         ldd   FD.SIZ,u		get file size
         ldx   FD.SIZ+2,u
         ldu   PD.Exten,y	get path extension pointer
         IFGT  Level-1
         cmpu  PE.Confl,u	head of the conflict tree?
         beq   Open209		yes, skip ahead
         ldu   PE.Confl,u	get the conflicting path ext. pointer
         ldu   PE.PDptr,u	get back pointer to the PD of conflicting process
* ldq PD.SIZ,u
         ldd   PD.SIZ,u		get his size instead
         ldx   PD.SIZ+2,u
         ENDC
* stq PD.SIZ,y
Open209  std   PD.SIZ,y		set file size in path descriptor of caller
         stx   PD.SIZ+2,y
         clr   PD.SMF,y		clear the state flags
ex       rts   			return


*
* I$MakDir Entry Point
*
* Entry: X = address of the pathlist
*
* Exit:  X = last byte of pathlist address
*
* Error: CC Carry set
*        B = errcode
*
MakDir   lbsr  Create		create a file descriptor
         bcs   MDir261		problem, return error
         lda   PD.ATT,y		get attributes
         ora   #SHARE.		set shareable bit
         lbsr  ChkAttrs		can user access directory?
         bcs   MDir261		no, return error
         ldd   #DIR.SZ*2	get default directory size (for '.' & '..')
         std   PD.SIZ+2,y	save it in path descriptor (MSW set to 0)
         bsr   MDir273		write out file descriptor
         bcs   MDir261		error, return
         lbsr  L0C6F
         bcs   MDir261
         lbsr  RdFlDscr		read in file descriptor
         ldu   PD.BUF,y		get pointer to file descriptor
         IFNE  H6309
         oim   #DIR.,FD.ATT,u	set directory bit in attributes
         ELSE
         lda   FD.ATT,u
         ora   #DIR.
         sta   FD.ATT,u
         ENDC
         bsr   MDir266
         bcs   MDir261
         lbsr  Creat170		clear out sector
         ldd   #$2EAE		get directory entry name for current & parent dir
         std   ,u		save parent name
         stb   DIR.SZ,u		save current name
* This is smaller and faster than the old method
*         ldq   PD.DFD-1,y	get directory FD pointer into low 24-bits of Q
*         clra			make sure high byte is zero
*         stq   DIR.FD-1,u	save in the dir: '.' and '..' have <28 char names
         lda   PD.DFD,y
         sta   DIR.FD,u
         ldd   PD.DFD+1,y
         std   DIR.FD+1,u
*         ldq   PD.FD-1,y	get current FD into lower 24-bits of Q
*         clra			ensure high byte is zero
*         stq   DIR.SZ+DIR.FD-1,u	save in the directory
         lda   PD.FD,y
         sta   DIR.SZ+DIR.FD,u
         ldd   PD.FD+1,y
         std   DIR.SZ+DIR.FD+1,u

         lbsr  L1205		flush new directory ssector to disk
MDir261  bra   Rt100Mem		return to system all ok

* Set new file size in file descriptor
* Entry: None
* Exit : New file size set in file descriptor on disk
MDir263  lbsr  RdFlDscr		read in file descriptor
MDir266  ldx   PD.BUF,y		get sector pointer
         IFNE  H6309
         ldq   PD.SIZ,y		get current file size
         stq   FD.SIZ,x		save it in file descriptor
         ELSE
         ldd   PD.SIZ,y
         std   FD.SIZ,x
         ldd   PD.SIZ+2,y
         std   FD.SIZ+2,x
         ENDC
         clr   PD.SMF,y		clear state flags
MDir273  lbra  L11FD


*
* I$Close Entry Point
*
* Entry: A = path number
*
* Exit:
*
* Error: CC Carry set
*        B = errcode
*
Close    clra  
         tst   PD.CNT,y		any open paths?
         bne   Clos29C		yes, return
         lbsr  L1237		flush current sector of needed
         bcs   Rt100Mem		error, skip ahead
         ldb   PD.MOD,y		get access mode
         bitb  #WRITE.		is it write?
         beq   Rt100Mem		no, skip ahead
         ldd   PD.FD,y
         bne   Clos290
         lda   PD.FD+2,y
         beq   Rt100Mem
Clos290  bsr   MDir263		set new file size in file descriptor
         lbsr  Gst5E5		reached EOF?
         bcc   Rt100Mem		no, skip ahead
         lbsr  L0EFE
         bra   Rt100Mem		skip ahead
Clos29C  rts   			return
* Return file not accessible error
Clos29D  ldb   #E$FNA
ErMemRtn coma  
Clos2A0  puls  y

* Generalized return to system
Rt100Mem pshs  b,cc		preserve error status
         ldu   PD.BUF,y		get sector buffer pointer
         beq   RtMem2CF		none, skip ahead
         ldd   #$0100		get size of sector buffer
         os9   F$SRtMem		return the memory to system
         ldx   PD.Exten,y	get path extension pointer
         beq   RtMem2CF		none, return
         lbsr  L0A90		scan conflict list?
         IFGT  Level-1
         lda   PE.PE,x		return path extension to system
         ldx   <D.PthDBT
         os9   F$Ret64
         ENDC
RtMem2CF puls  pc,b,cc		restore error status & return

* Place date & time into file descriptor
L02D1    lbsr  RdFlDscr		read in file descriptor sector
         ldu   PD.BUF,y		get pointer to it
         lda   FD.LNK,u		get link count
         ldx   <D.Proc		get current process pointer
         pshs  x,a		preserve 'em
         ldx   <D.SysPrc	switch to system process descriptor
         stx   <D.Proc
         leax  FD.DAT,u		point to date last modified
         os9   F$Time		put currenttime there
* Gene Heskett's STUPID "LDA #$01, STA $00FF,u" CRAP went here. DAMN DAMN DAMN
* He's NEVER getting the RBF source again!
         puls  x,a		restore link count & current process
         stx   <D.Proc
         sta   FD.LNK,u
         rts   			return


*
* I$ChgDir Entry Point
*
* Entry:
*
* Exit:
*
* Error: CC Carry set
*        B = errcode
*
ChgDir   pshs  y		preserve path descriptor pointer
         IFNE  H6309
         oim   #$80,PD.MOD,y	ensure the directory bit is set
         ELSE
         lda   PD.MOD,y
         ora   #$80
         sta   PD.MOD,y
         ENDC
         lbsr  Open		go open the directory
         bcs   Clos2A0		exit on error
         ldx   <D.Proc		get current process pointer
         ldu   PD.FD+1,y	get LSW of file descriptor sector #
         ldb   PD.MOD,y		get current file mode
         bitb  #UPDAT.		read or write mode?
         beq   CD30D		no, skip ahead
* Change current data dir
         ldb   PD.FD,y
         stb   P$DIO+3,x
         stu   P$DIO+4,x
CD30D    ldb   PD.MOD,y		get current file mode
         bitb  #EXEC.		is it execution dir?
         beq   CD31C		no, skip ahead
* Change current execution directory
         ldb   PD.FD,y
         stb   P$DIO+9,x
         stu   P$DIO+10,x
CD31C    clrb  			clear errors
         bra   Clos2A0		return to system


*
* I$Delete Entry Point
*
* Entry:
*
* Exit:
*
* Error: CC Carry set
*        B = errcode
*
* NOTE: Bug for write protected disk has been fixed - 93/09/19
*
Delete   
         pshs  y		preserve path descriptor pointer
         lbsr  FindFile		does the file exist?
         bcs   Clos2A0		no, return error
         ldd   PD.FD+1,y	do we have a file descriptor?
         bne   Del332		yes, skip ahead
         tst   PD.FD,y
         lbeq  Clos29D
Del332   lda   #SHARE.+WRITE.	get attributes to check
         lbsr  ChkAttrs		can user delete ths file?
         lbcs  Clos2A0		no, return error
         ldu   PD.RGS,y		get registered stack pointer
         stx   R$X,u		save updated pathname pointer
         lbsr  RdFlDscr		read in file descriptor
* BUG FIX: Below used to read 'lbcs L03D4' which expects the file descriptor
*          sector # & a temporary buffer to be stored on the stack but it
*          isn't there yet.  Restored back to RBF 28 error handling
*         lbcs  L02B2		error, return to system (FD read error fix)
         lbcs  Del3D4		error, rturn to system (FD read error fix)
         ldx   PD.BUF,y		get pointer to the file descriptor
         dec   FD.LNK,x		decrement link count
         beq   Del358		down to zero, delete the file descriptor
         lbsr  L11FD		write updated file descriptor
         pshs  u,x,b
         IFNE  H6309
         clrd  
         ELSE
         clra  
         clrb  
         ENDC
         std   $03,s
         bra   Del39F

* RBF30 start
Del358   ldb   PD.FD,y		get LSN of file descriptor
         ldx   PD.FD+1,y
         pshs  u,x,b		preserve 'em
         ldd   #$0100		allocate a temporary sector buffer
         os9   F$SRqMem
         bcc   Del36C		got it, skip ahead
         IFNE  H6309
         clrd  
         ELSE
         clra  
         clrb  
         ENDC
         bra   Del37A		return with eror

Del36C   stu   $03,s		save pointer to sector buffer
         ldx   PD.BUF,y
         IFNE  H6309
         ldw   #$0100
         tfm   x+,u+		copy the sector
         ELSE
         clrb
DelLoop  lda   ,x+
         sta   ,u+
         decb
         bne   DelLoop
         ENDC
         ldd   $03,s
Del37A   std   $03,s		save buffer pointer to U on stack
* Start back into RBF28 code again
         IFNE  H6309
         clrd  
         ELSE
         clra  
         clrb  
         ENDC
         std   PD.SIZ,y		set file size to zero
         std   PD.SIZ+2,y
         lbsr  L0EFE		set the file size to PD.SIZ
         bcs   Del3EF
         ldb   PD.FD,y		grab file descriptor sector number
         ldx   PD.FD+1,y
         stb   PD.SBP,y		copy it to the segment beginning sector number
         stx   PD.SBP+1,y
         ldx   PD.BUF,y		point to the buffer
* RBF34
* LDD $13,X    : FD.SEG+3, grab the size of the FIRST segment of the file
* addd #$0001
* THEN std PD.SSZ+1,y
*
* Why?  RBF automatically makes the FIRST SEGMENT of the file fill the rest
* of the cluster that was allocated for the file descriptor.
* Why not LDX PD.DTB,y  LDD DD.BIT,x  ???
*
* Gene H: My problem with this fix from rbf28 is in proving to me
* $13,x is the correct location to read! I can't seem to find
* the defines to match the $13,x address.
*         ldd   FD.SEG+FDSL.B,x	grab the size of the first segment
         ldd   <$13,x		this code is REQUIRED for multiple
         IFNE  H6309
         incd			sector/cluster operation, don't remove!
         ELSE
         addd  #$0001 sector cluster operation, DO NOT REMOVE!
         ENDC
         std   PD.SSZ+1,y
         lbsr  ClrFBits		delete a segment
Del39F   bcs   Del3EF
         lbsr  L1237		flush the sector
         lbsr  L0A90
         lda   PD.DFD,y
         sta   PD.FD,y
         ldd   PD.DFD+1,y
         std   PD.FD+1,y
         lbsr  RdFlDscr		get the file descriptor
         bcs   Del3EF
         lbsr  L0A2A
         ldu   PD.BUF,y
         lbsr  Open1CE		update PD entries from FD entries
         IFNE  H6309
         ldq   PD.DCP,y		get current directory entry pointer
         stq   PD.CP,y		save it as current pointer
         ELSE
         ldd   PD.DCP,y
         std   PD.CP,y
         ldd   PD.DCP+2,y
         std   PD.CP+2,y
         ENDC
         lbsr  L0957		read in the directory sector
         bcs   Del3EF
         clr   ,x		clear first byte of filename in directory entry
         lbsr  L1205		flush the sector to disk
* RBF30 start
Del3D4   ldu   $03,s		get temporary sector buffer pointer
* the patch at Del3EF-3F9 munged the stack for this one - GH
         beq   Del3F9		none allocated, return to process
         ldb   ,s		get the old file descriptor logical sector #
         ldx   $01,s
         stb   PD.FD,y		put it back into path descriptor
         stx   PD.FD+1,y
         ldx   PD.BUF,y		get current sector buffer pointer
         stx   1,s		save it a sec
         stu   PD.BUF,y		put original sector pointer into path descriptor
         lbsr  L11FD		write the old file descriptor to disk
         ldu   1,s		get temporary sector pointer
         stu   PD.BUF,y		save it as current
Del3EF   pshs  b,cc		preserve rror status & code if any (WP bug fix - raises stack offsets+2)
         ldu   $05,s		get temporary sector buffer pointer (this was a 3)
         beq   Del3F5		didn't allocate one, skip ahead (different, new label! no mem to return)
         ldd   #$0100		get size of it
         os9   F$SRtMem		return the memory back to the system
Del3F5   puls  b,cc		restore error status & code (WP bug fix)
Del3F9   leas  5,s		purge stack
* Start back into RBF28 code
         lbra  Clos2A0		return to system


*
* I$Seek Entry Point
*
* Entry:
*
* Exit:
*
* Error: CC Carry set
*        B = errcode
*
Seek     ldb   PD.SMF,y		get state flags
         bitb  #SINBUF		do we have a sector in buffer?
         beq   Seek417		no, skip ahead
         lda   R$X+1,u		calculate if we need a new sector
         ldb   R$U,u
         subd  PD.CP+1,y
         bne   Seek412
         lda   R$X,u
         sbca  PD.CP,y
         beq   Seek41B		no need to get another sector, skip ahead
Seek412  lbsr  L1237		flush the current sector to disk
         bcs   Seek41F
Seek417  ldd   R$X,u		get & set new file pointer
         std   PD.CP,y
Seek41B  ldd   R$U,u
         std   PD.CP+2,y
Seek41F  rts   			return


*
* I$ReadLn Entry Point
*
* Entry:
*
* Exit:
*
* Error: CC Carry set
*        B = errcode
*
ReadLn   bsr   RdLn463		check if record locked for amount to be read
         beq   RdLn446		zero bytes to read, return
         bsr   RdLn447
         pshs  u,y,x,b,a
         exg   x,u
         IFNE  H6309
         tfr   0,y		smaller, same speed as LDY #$0000
         ELSE
         ldy   #$0000
         ENDC
         lda   #$0D		a carriage return
RdLn430  leay  1,y		go up one byte
         cmpa  ,x+		is it a CR?
         beq   RdLn439		yes, we're done
         decb  			count down
         bne   RdLn430		until done one sector, at least
RdLn439  ldx   6,s		get old U
         bsr   RdLn49B		move bytes from the system to user
         sty   $0A,s		save Y on-stack, above calling routine????
         puls  u,y,x,b,a	restore registers
         ldd   $02,s		get old saved Y from above
*         addr  d,x
         leax  d,x		point to how many bytes we've read
RdLn446  rts   			and exit

RdLn447  lbsr  Read4D3		do reading, calling this routine back again
         leax  -1,x		back up a byte
         lbsr  L097F		get a byte from another task (F$LDABX)
         cmpa  #$0D		is it a CR?
         beq   RdLn459		yes, skip ahead
         ldd   $02,s		check data saved on-stack???
         bne   Read4D9		if not zero, skip ahead
RdLn459  ldu   PD.RGS,y		grab caller's register stack
         ldd   R$Y,u		get number of bytes to read
         subd  $02,s		take out data read last sector??
         std   R$Y,u		save as data bytes to read
         bra   Read4C0		skip ahead

* Calculate if read will be record locked with another process
* Entry: U=Register stack pointer
RdLn463  ldd   R$Y,u		get requested read length
         lbsr  L0B0C		record locked with somebody else?
         bcs   RdLn497		yes, return deadlock error
         ldd   R$Y,u		get requested read length
         bsr   RdLn473		calculate if we will have an EOF error
         bcs   RdLn497		we did, return error
         std   R$Y,u		save # bytes available
         rts   			return

* Calculate if read length will overrun file length
* Entry: D=Requested # bytes to read from file
* Exit : D=# bytes available
RdLn473  pshs  d		preserve length
         IFNE  H6309
         ldq   PD.SIZ,y		get current file size
         subw  PD.CP+2,y	subtract off LSW of current byte pointer
         tfr   w,x		save it in the old register
         sbcd  PD.CP,y		subtract off current byte pointer
         ELSE
         ldd   PD.SIZ+2,y
         subd  PD.CP+2,y
         tfr   d,x
         ldd   PD.SIZ,y
         sbcb  PD.CP+1,y
         sbca  PD.CP,y
         ENDC
         bcs   RdLn494		it will overrun, return EOF error
         bne   RdLn491		some bytes left, return OK
         tstb  
         bne   RdLn491
         cmpx  ,s		do we have enough bytes?
         bhs   RdLn491		yes, return OK
         stx   ,s		save # bytes available
         beq   RdLn494		it's 0, return EOF error
RdLn491  clrb  			clear error status
         puls  pc,b,a		retrieve # bytes & return
* Return EOF error
RdLn494  comb  			set carry for error
         ldb   #E$EOF		get error code
RdLn497  leas  $02,s		purge length off stack
         bra   Read4C5		return

* Move bytes from system to user
* Entry: X=Source pointer
*        Y=Byte count
*        U=Destination pointer
RdLn49B  pshs  x
         ldx   <D.Proc		get current process pointer
         lda   <D.SysTsk	get source task #
         ldb   P$Task,x		get destination task #
         puls  x
         os9   F$Move		move 'em
         rts   			return


*
* I$Read Entry Point
*
* Entry:
*
* Exit:
*
* Error: CC Carry set
*        B = errcode
*
Read     bsr   RdLn463		record locked?
         beq   Read4BB		no, allow it
         bsr   Read4BC		do reading
Read4AF  pshs  u,y,x,b,a	save data on the stack
         exg   x,u
         tfr   d,y
         bsr   RdLn49B		move bytes from system to user
         puls  u,y,x,b,a	restore registers
*         addr  d,x
         leax  d,x		point to end of data copied?
Read4BB  rts   

Read4BC  bsr   Read4D3		do some reading/writing
         bne   Read4D9		not done, continue
Read4C0  clrb  
Read4C1  leas  -2,s		clear out crap on the stack
Read4C3  leas  $0A,s
* Error processor for read & write
Read4C5  pshs  b,cc		preserve error status
         lda   PD.MOD,y		get file mode
         bita  #WRITE.		was it write?
         bne   Read4D0		yes, return
         IFGT  Level-1
         lbsr  L0B02		clear lock status, and send signals
         ENDC
Read4D0  puls  b,cc,pc		restore & return

* do reading/writing
Read4D3  ldd   R$X,u		get caller's buffer pointer
         ldx   R$Y,u		get length of read
         pshs  x,b,a		preserve 'em
Read4D9  lda   PD.SMF,y		get stat flags
         bita  #SINBUF		sector in buffer/
         bne   Read4F9		yes, read it
         tst   PD.CP+3,y	read pointer on even sector?
         bne   Read4F4		no, skip ahead
         tst   $02,s		MSB of length have anything?
         beq   Read4F4		no, skip ahead
         leax  >Writ571,pcr	WritLn or ReadLn?
         cmpx  $06,s		check the stack
         bne   Read4F4		skipahead
         lbsr  L1098		find a segment
         bra   Read4F7

Read4F4  lbsr  L1256
Read4F7  bcs   Read4C1
Read4F9  ldu   PD.BUF,y		get sector buffer pointer
         clra  
         ldb   PD.CP+3,y
*         addr  d,u
         leau  d,u		point to offset within the buffer
         negb  			get D=number of byte left to read in the sector?
         sbca  #$FF		not quite sure what this is...
         ldx   ,s		grab caller's buffer pointer
         cmpd  $02,s		check bytes left in sector against number to read
         bls   Read50C		lower, OK
         ldd   $02,s		grab number of bytes to read
Read50C  pshs  b,a		save
         jsr   [$08,s]		call our calling routine!
         stx   $02,s		save new address to write to on-stack
         IFNE  H6309
         aim   #^BufBusy,PD.SMF,y
         ELSE
         ldb   PD.SMF,y
         andb  #^BufBusy
         stb   PD.SMF,y
         ENDC
         ldb   $01,s		get LSB of bytes read
         addb  PD.CP+3,y	add it to current pointer
         stb   PD.CP+3,y	save new file position
         bne   Read530		didn't grab whole sector, skip ahead
         lbsr  L1237		flush the sector
         inc   PD.CP+2,y	add
         bne   Read52E
         inc   PD.CP+1,y
         bne   Read52E
         inc   PD.CP,y
Read52E  bcs   Read4C3
Read530  ldd   $04,s		grab number of bytes to read/write
         subd  ,s++		take out number we've read/written
         std   $02,s		save on-stack
         jmp   [$04,s]		go back to calling routine with D,X on-stack


*
* I$WritLn Entry Point
*
* Entry:
*
* Exit:
*
* Error: CC Carry set
*        B = errcode
*
WriteLn  pshs  y		save PD pointer
         clrb  
         ldy   R$Y,u		grab size of data to write
         beq   WtLn55E		exit if none
         ldx   <D.Proc		get process descriptor pointer
         ldb   P$Task,x		grab task number
         ldx   R$X,u		and where to get data from
* ATD: Could make this quite a bit larger, and probably faster, by doing the
* PipeMan-style copy 32 bytes onto the stack via F$Move, and check that.
* Doing F$LDABX for a lot of data is _really_ slow.  PipeMan test indicate
* that it could probably double in speed...
WtLn547  leay  -$01,y		back up one byte
         beq   WtLn55E		if done, exit
         os9   F$LDABX		grab one byte from the user
         leax  $01,x		go up a byte
         cmpa  #$0D		is it a CR?
         bne   WtLn547		no, keep it up until done
         tfr   y,d		get number of bytes left
         nega             \
* a negd was tried here, but may have caused runaway writes>64k
         negb             /	invert it
         sbca  #$00
         addd  R$Y,u		add to bytes to write
         std   R$Y,u		save new number of bytes to write
WtLn55E  puls  y		restore PD pointer, and fall through to Write


*
* I$Write Entry Point
*
* Entry:
*
* Exit:
*
* Error: CC Carry set
*        B = errcode
*
Write    ldd   R$Y,u		get size of write
         lbsr  L0B0C		wait for I/O lock
         bcs   Writ598		error, return
         ldd   R$Y,u		get size again
         beq   Writ597		zero, nothing to write so return
         bsr   Writ599		expand the file if needed
         bcs   Writ598		error on expand, return
         bsr   Writ582
Writ571  pshs  y,b,a
         tfr   d,y
         bsr   Writ5CB
         puls  y,b,a
         leax  d,x
         IFNE  H6309
         oim   #(BUFMOD!SINBUF),PD.SMF,y
         ELSE
         pshs  a
         lda   PD.SMF,y
         ora   #(BUFMOD!SINBUF)
         sta   PD.SMF,y
         puls  a
         ENDC
         rts   

Writ582  lbsr  Read4D3		go read stuff
         lbne  Read4D9
         leas  $08,s		skip stuff on stack
         ldy   PD.Exten,y
         lda   #$01
         lbsr  L0AD1
         ldy   PE.PDptr,y
Writ597  clrb  
Writ598  rts   

* Add bytes to current file position with file length extension
* Entry: D=# bytes to add
Writ599  addd  PD.CP+2,y	add length to LSW of current pointer
         tfr   d,x		copy it
         ldd   PD.CP,y		get MSW
         IFNE  H6309
         adcd  #0		add in any carry from above
         ELSE
         adcb  #0
         adca  #0
         ENDC
Writ5A3  cmpd  PD.SIZ,y		MSW past eof?
         bcs   Writ597		no, return
         bhi   Writ5AF		yes, add a sector
         cmpx  PD.SIZ+2,y	LSW past eof?
         bls   Writ597		no, return
Writ5AF  pshs  u		preserve U
         ldu   PD.SIZ+2,y	get LSW of current size
         stx   PD.SIZ+2,y	save new size
         ldx   PD.SIZ,y		get MSW of new size
         std   PD.SIZ,y		save new size
* ATD: L0C6F looks like it already saves U and X, so saving them here is
* unnecessary.
         pshs  u,x		preserve old size
         lbsr  L0C6F		allocate new size of file
         puls  u,x		restore old size
         bcc   Writ5C9		no error from allocate, return
         stx   PD.SIZ,y		put old size back
         stu   PD.SIZ+2,y
Writ5C9  puls  pc,u		restore U & return

* Move bytes from user to system
* Entry: X=Source pointer
*        Y=Byte count
*        U=Destination pointer
Writ5CB  pshs  x
         ldx   <D.Proc		get source task #
         lda   P$Task,x
         ldb   <D.SysTsk	get destination task #
         puls  x
         os9   F$Move		move 'em
         rts   			return


*
* I$GetStat Entry Point
*
* Entry:
*
* Exit:
*
* Error: CC Carry set
*        B = errcode
*
GetStat  ldb   R$B,u		get function code
         beq   Gst5FF		it's SS.Opt, go process
         cmpb  #SS.EOF		EOF check?
         bne   Gst5EB		no, skip ahead
         clr   R$B,u		default to no EOF
Gst5E5   clra  			get length & clear carry
         ldb   #$01
         lbra  RdLn473		go calculate EOF status & return

* SS.Ready
* check for data avail on dev
* Entry A=path number
*       B=$01
Gst5EB   cmpb  #SS.Ready	is it SS.Ready?
         bne   Gst5F2		no, keep checking
         clr   R$B,u		always mark no data ready
         rts   

* SS.SIZ
* Entry A=path num
*       B=$02
* Exit  X=msw of files size
*       U=lsw of files size
Gst5F2   cmpb  #SS.Size		is it SS.Size?
         bne   Gst600		no, keep checking
         IFNE  H6309
* faster and smaller than 2 LDD's, PD.SIZ+2 >$0F, so we can't use short n,R
         ldq   PD.SIZ,y		get current file size
Gst5F8   std   R$X,u		save to the user
         stw   R$U,u		save LSW
         ELSE
         ldd   PD.SIZ,y
         std   R$X,u
         ldd   PD.SIZ+2,y
         std   R$U,u
         ENDC
Gst5FF   rts   			return

* SS.Pos
* Entry A=path num
*       B=$05
* Exit  X=msw of pos
*       U=lsw of pos
Gst600   cmpb  #SS.Pos		is it SS.Pos?
         bne   Gst60D		no, keep checking
         IFNE  H6309
* use 2 LDD, STD, same size as ldq/std/stw, PD.CP+2 <$0F, we can use short n,R
         ldq   PD.CP,y		get current file pointer
         bra   Gst5F8
         ELSE
         ldd   PD.CP,y		get current file pointer
         std   R$X,u		save MSW
         ldd   PD.CP+2,y	get current file pointer
         std   R$U,u		save LSW
         rts
         ENDC

* Getstt(SS.FD)
* Entry: R$A = Path #
*        R$B = SS.FD ($0F)
*        R$X = ptr to 256 byte buffer
*        R$Y = # of bytes of FD required
Gst60D   cmpb  #SS.FD		is it SS.FD?
         bne   Gst627		no, keep checking
         lbsr  RdFlDscr		go get file descriptor
         bcs   Gst5FF		exit on error
         ldu   PD.RGS,y		get register stack pointer
         ldd   R$Y,u		get # bytesof FD he wants
         tsta  			legal value?
         beq   Gst620		yes, skip ahead
         ldd   #$0100		get max size of FD
Gst620   ldx   R$X,u		get pointer
         ldu   PD.BUF,y		get pointer to FD
         lbra  Read4AF		move it to user space

* Getstt(SS.FDInf)
* Entry: R$A = Path #
*        R$B = SS.FDInf ($20)
*        R$X = ptr to 256 byte buffer
*        R$Y = msb - Length of read
*              lsb - MSB of LSN
*        R$U = LSW of LSN
Gst627   cmpb  #SS.FDInf	SS.FDInf?
         bne   Gst640		no, let driver handle it
         lbsr  L1237		check for sector flush
         bcs   Gst5FF
         ldb   R$Y,u		get MSB of sector #
         ldx   R$U,u		get LSW of sector #
         lbsr  L113A		read the sector
         bcs   Gst5FF		error, return
         ldu   PD.RGS,y		get register stack pointer
         ldd   R$Y,u		get length of data to move
         clra  			clear MSB
         bra   Gst620		move it to user

* Let driver handle the rest
Gst640   lda   #D$GSTA		get getstat function offset
         lbra  L113C		send it to driver


*
* I$SetStat Entry Point
*
* Entry:
*
* Exit:
*
* Error: CC Carry set
*        B = errcode
*
SetStat  ldb   R$B,u		get function code
* TODO: remove next line since SS.Opt is 0
         cmpb  #SS.Opt
         bne   Sst659		not SS.Opt, skip ahead
         ldx   R$X,u		get pointer to option packet
         leax  $02,x		skip device type and drive #
         leau  PD.STP,y		get pointer to start of data
         ldy   #(PD.TFM-PD.STP)	get # bytes to move (not including PD.TFM)
         lbra  Writ5CB		move 'em & return

* SS.Size
Sst659   cmpb  #SS.Size		is it SS.Size?
         bne   Sst69B
         ldd   PD.FD+1,y	is there a file descriptor?
         bne   Sst669
         tst   PD.FD,y
         lbeq  Sst7A8		no, return error
Sst669   lda   PD.MOD,y		get file mode
         bita  #WRITE.		is it write?
         beq   Sst697		no, return error
         ldd   R$X,u		get MSW of new size
         ldx   R$U,u		get LSW of new size
         cmpd  PD.SIZ,y
         bcs   Sst682
         bne   Sst67F
         cmpx  PD.SIZ+2,y
         bcs   Sst682
* New size is larger
Sst67F   lbra  Writ5A3		add new size to file
* New size is smaller
Sst682   std   PD.SIZ,y
         stx   PD.SIZ+2,y
         ldd   PD.CP,y
         ldx   PD.CP+2,y
         pshs  x,b,a
         lbsr  L0EFE		delete from end of the file
         puls  u,x
         stx   PD.CP,y		restore current position
         stu   PD.CP+2,y
         rts   
* Return bad mode error
Sst697   comb  			set carry
         ldb   #E$BMode		get bad mod error
Sst69A   rts   			return

* SetStt(SS.FD) #$0F - returns FD to disk
* Entry: R$A = Path #
*        R$B = SS.FD ($0F)
*        R$X = ptr to 256 byte buffer
*        R$Y = # bytes to write
Sst69B   cmpb  #SS.FD		is it SS.FD?
         bne   Sst6D9		no, keep checking
         lda   PD.MOD,y
         bita  #WRITE.		is it write mode?
         beq   Sst697		no, return bad mode error
         lbsr  RdFlDscr		read in file descriptor
         bcs   Sst69A		error, return
         pshs  y		preserve path descriptor pointer
         ldx   R$X,u		get pointer to caller's buffer
         ldu   PD.BUF,y		get pointer to FD
         ldy   <D.Proc		get current process pointer
         ldd   P$User,y		get user #
         bne   Sst6BC		not super user, skip ahead
* Change owner of file
         ldd   #$0102		get offset & # of bytes to move
         bsr   Sst6CB
* Change date last modified
Sst6BC   ldd   #$0305
         bsr   Sst6CB
* Change creation date
         ldd   #$0D03
         bsr   Sst6CB
         puls  y
         lbra  L11FD
* Offset into FD sector
* Entry: A=# bytes to offset
*        B=# bytes to put
Sst6CB   pshs  u,x
         leax  a,x
         leau  a,u
         clra  
         tfr   d,y
         lbsr  Writ5CB
         puls  pc,u,x

Sst6D9   cmpb  #SS.Lock		is it SS.Lock?
         bne   Sst6F8		no, keep checking
         ldd   R$U,u		get MSW of size
         ldx   R$X,u		get LSW of size
         cmpx  #$FFFF		lock whole file?
         bne   Sst6F5		no, skip ahead
         cmpx  R$U,u
         bne   Sst6F5		after this line, we're SURE that D=$FFFF
         ldu   PD.Exten,y
         IFNE  H6309
         oim   #FileLock,PE.Lock,u
         ELSE
         lda   PE.Lock,u
         ora   #FileLock
         sta   PE.Lock,u
         ENDC
* ATD: This next line is unnecessary after the check done, above
         lda   #$FF		?? if X=$FFFF, then D=$FFFF too.
Sst6F5   lbra  L0B1B

* SS.Ticks
Sst6F8   cmpb  #SS.Ticks	is it SS.Ticks?
         bne   Sst705		no, keep checking
         ldd   R$X,u		get # of ticks
         ldx   PD.Exten,y	put it into path extension
         std   PE.TmOut,x
         rts   			return

* SS.RsBit 
Sst705   cmpb  #SS.RsBit	reserve bitmap sector?
         bne   Sst715		no, keep checking
         ldx   PD.DTB,y		get drive table pointer
         lda   R$X+1,u		get sector #
         sta   V.ResBit,x	put it into drive table
         clr   V.MapSct,x	clear mapped sector
Sst714   rts   			return

* SS.Attr 
Sst715   cmpb  #SS.Attr		is it SS.Attr?
         bne   Sst784		no, keep checking
         lbsr  RdFlDscr		get the file descriptor from drive
         bcs   Sst714		error, return
         ldx   <D.Proc		get pointer to current process
* Note, should'nt this be lda?  User number is 8 bits, not 16
         ldd   P$User,x		get user number
         beq   Sst72A		it's super user, skip ahead
         ldx   PD.BUF,y		get pointer to FD
         cmpd  FD.OWN,x		user # match owner of file?
         bne   Sst780		no, return not accessible error
Sst72A   lda   R$X+1,u		get attributes from caller
         tfr   a,b		copy it
         ldu   PD.BUF,y		get pointer to FD
         eorb  FD.ATT,u		directory bit set?
         bpl   Sst77B		no, save new attributes & return
         tsta  			is user setting directory bit?
         bmi   Sst764		yes, return directory not empty error
* Directory attributes changing, check if it's root dir
         ldx   PD.DTB,y		get pointer to drive table
         ldd   DD.DIR,x		get MSW of sector # to root directory
         cmpd  PD.FD,y		match current FD sector #?
         bne   Sst749		no, skip ahead
         ldb   DD.DIR+2,x	get LSB of sector # to root directory
         cmpb  PD.FD+2,y	match current FD sector #?
         beq   Sst780		yes, return not accessible error
* Scan directory to see if there's any files and/or directories
Sst749   ldb   PD.CP,y		get current directory entry pointer
         ldx   PD.CP+1,y
         pshs  x,b		preserve it
* ATD: there should be a CLRD here
         std   PD.CP,y		??? This code doesn't look correct...
* ATD: should be DIR.SZ*2: so we skip '..' and '.'
         ldb   #DIR.SZ
         std   PD.CP+2,y
Sst755   lbsr  L0942		move to next filename in directory
         bcs   Sst768		error in read, check for EOF
         tst   ,x		filename exist?
         beq   Sst755		no, keep looking
         puls  x,b		restore current pointer
         stb   PD.CP,y
         stx   PD.CP+1,y
* Report directory not empty error
Sst764   ldb   #E$DNE		get directory not empty error
         bra   Sst782		return
Sst768   puls  x,a		restore current pointer
         sta   PD.CP,y
         stx   PD.CP+1,y
         cmpb  #E$EOF		at the end of directory?
         bne   Sst782		no, some other error
         lbsr  RdFlDscr		get file descriptor from drive
         ldu   PD.BUF,y		get sector pointer
         ldx   PD.RGS,y		get register stack pointer
         lda   R$X+1,x		get attributes
Sst77B   sta   FD.ATT,u		set 'em
         lbra  L11FD		write FD to disk & return
* Return file not accessible
Sst780   ldb   #E$FNA		get file not accessible error
Sst782   coma  			set carry
         rts   			return

* SetStt(SS.FSig)
Sst784   cmpb  #SS.FSig		SS.FSig send signal on write
         bne   Sst7A3
         lda   PD.ATT,y
         bita  #SHARE.
         lbne  L0A8B
         ldx   PD.Exten,y
         lda   R$X+1,u
         sta   PE.SigSg,x
         ldu   <D.Proc
         lda   P$ID,u		was <P$ID,u
         sta   PE.SigID,x
         clrb  
         rts   

Sst7A3   lda   #D$PSTA		call the driver SetStt routine
         lbra  L113C

Sst7A8   comb  
         ldb   #E$UnkSvc	unknown service request
Sst7AB   rts   


* Find a file in current data/execution directory
* Called by Create/Open & Delete
*
* Entry: U=caller's stack reg. ptr
*        Y=Path dsc. ptr
FindFile 
**** ADDED 06/19/2004 ****
* Call to SS.VarSect in Driver:
*
* This code calls the driver's SS.VarSect GetStat, which will
* update the PD.TYP byte in the path descriptor to the sector
* size of the media to which this path references.
* If the driver doesn't support the GetStat, it will return
* an error, and won't touch the PD.TYP anyway, so we ignore it.
         ldx   PD.RGS,y		get caller's regs
         lda   R$B,x		get caller's B
         pshs  x,a		save PD.RGS ptr and caller's original B
         ldd   #D$GSTA*256+SS.VarSect	getstat function/SS.VarSect GetStat
         stb   R$B,x		put SS.VarSect into caller's B
         lbsr  L113C		send it to driver
         puls  a,x		get caller's original B and saved PD.RGS
         sta   R$B,x		restore caller's original B
         bcc   ok@		branch if no error on GetStat
         cmpb  #E$UnkSvc	Unknown Service call error?
         bne   Sst782		if not, return with error
****
ok@      ldd   #$0100		get size of sector
* Note, following line is stb PD.SMF,y in v30!
         IFGT  Level-1
         stb   PD.FST,y		clear state flags??
         ENDC
         os9   F$SRqMem		request a 256 byte sector buffer
         bcs   Sst7AB		couldn't get memory, return with error
         stu   PD.BUF,y		save ptr to sector buffer
         IFGT  Level-1
         leau  ,y		point U to path descriptor
         ldx   <D.PthDBT	get ptr to path descriptor block tables
         os9   F$All64		allocate path descriptor
         exg   y,u		exchange pointers
         bcs   Sst7AB		couldn't get path descriptor, return error
         stu   PD.Exten,y	save pointer to path extension
         clr   PE.SigID,u	clear send signal proc. ID
         sty   PE.PDptr,u	save back pointer to path descriptor
         stu   PE.Wait,u	init waiting extension to myself
         ENDC
         ldx   PD.RGS,y		get register stack pointer
         ldx   R$X,x		get pointer to pathname
         pshs  u,y,x
         leas  -$04,s		make a buffer
         IFNE  H6309
         clrd
         ELSE
         clra  
         clrb  
         ENDC
         sta   PD.FD,y		init file descriptor logical sector #
         std   PD.FD+1,y
         std   PD.DSK,y		init disk ID
         lbsr  L097F		get a byte from caller's X
         sta   ,s		save it
         cmpa  #PDELIM		is it a device?
         bne   Sst7FB		no, skip ahead
         lbsr  GtDvcNam		go parse it
         sta   ,s		save last character
         lbcs  L090D		error in parse, return
         leax  ,y		point X to last character
         ldy   $06,s		get path descriptor pointer
         bra   Sst81E		skip ahead
Sst7FB   anda  #$7F		strip high bit
         cmpa  #PENTIR		entire device flag?
         beq   Sst81E		yes, go process
         lda   #PDELIM		place delimiter as last char
         sta   ,s
         leax  -$01,x		bump path pointer back 1
         lda   PD.MOD,y		get file mode
         ldu   <D.Proc		get pointer to current process
         leau  P$DIO,u		point to default data directory FD sector #
         bita  #EXEC.		does he want execution dir?
         beq   Sst814		no, skip ahead
         leau  $06,u		point to execution dir
Sst814   ldb   $03,u		get LSB of logical sector # of FD to dir
         stb   PD.FD,y		put it in path descriptor
         ldd   $04,u		get MSW of logical sector # of FD to dir
         std   PD.FD+1,y
Sst81E   ldu   PD.DEV,y		get pointer to device table
         stu   PD.DVT,y		copy it for user
         lda   PD.DRV,y		get drive #
         ldb   #DRVMEM		get sizeof drive tables
* confusion reigns supreme here - NO MORE!
* The data stored at L0012 *IS* the drive table sizeof.
* MY question is why this RBF constant is stored as a variable.
* Why would it need to be changed, and by who?
         mul   			calculate offset into drive tables
         addd  V$STAT,u		add start of static memory
         addd  #DRVBEG		add offset to drive tables
         std   PD.DTB,y		save pointer to drive table
         lda   ,s		get character back
         anda  #$7F		strip high bit
         cmpa  #PENTIR		was it entire flag?
         bne   Sst83F		no, keep going
         leax  $01,x		move to next character
         bra   Sst861		go on

Sst83F   lbsr  L1110		read in LSN0
         lbcs  L0915		error, return
         ldu   PD.BUF,y		get sector buffer pointer from the read-in sector
* otherwise use the pointer from PD.DTB
         ldd   DD.DSK,u		get disk ID
         std   PD.DSK,y		put it in path descriptor
         ldd   PD.FD+1,y	does it have a file descriptor?
         bne   Sst861		yes, skip ahead
         lda   PD.FD,y
         bne   Sst861
         lda   DD.DIR,u		get LSN of root directory
         sta   PD.FD,y		put it in path descriptor
         ldd   DD.DIR+1,u
         std   PD.FD+1,y
Sst861   stx   $04,s		save pointer to pathname
         stx   $08,s

Sst865   lbsr  L1237		flush sector buffer
         lbcs  L0915		error, exit
         lda   ,s		get last character of pathname
         anda  #$7F		mask off high bit
         cmpa  #PENTIR		entire device flag?
         beq   Sst87B		yes, skip ahead
         lbsr  RdFlDscr		read in file descriptor
         lbcs  L0915		error, return
Sst87B   lbsr  L0A2A		check if directory is busy
         lda   ,s
         cmpa  #PDELIM		was the trailing character a slash?
         bne   L08EF		no, skip ahead
         clr   $02,s
         clr   $03,s
         lda   PD.MOD,y		get file mode
         ora   #DIR.		mask in directory bit
         lbsr  ChkAttrs		can user access directory?
         bcs   L090D		no, return
         lbsr  Open1CE		setup path descriptor & start scan
         ldx   $08,s		get pathname pointer
         leax  $01,x		bump to next character
         lbsr  GtDvcNam		check for valid name
         std   ,s		save length of name
         stx   $04,s		save updated name pointer
         sty   $08,s
         ldy   $06,s		get path descriptor pointer
         bcs   L090D		error in pathname, return
         IFGT  Level-1
         pshs  u,y
         ldu   PD.Exten,y	get pointer to path extension
         leau  PE.FilNm,u	point to filename buffer
         clra  			clear MSB of name length
         tfr   d,y		move it to Y
         lbsr  Writ5CB		move filename to temp area
         puls  u,y
         ENDC
         lbsr  L0957		read in a directory sector
         bra   L08C1

* Scan diretory for name
L08BC    bsr   L0918		get file descriptor
         IFNE  H6309
L08BE    bsr   L0942		get next directory entry from drive
         ELSE
L08BE    lbsr  L0942
         ENDC
L08C1    bcs   L090D		error,
         tst   ,x		filename exists?
         beq   L08BC		no, get next entry
         clra  
         ldb   $01,s
         exg   x,y
         ldx   PD.Exten,x	get path extension pointer
         leax  PE.FilNm,x	point to user's filename
         lbsr  L09BF		compare the names
         ldx   $06,s		get pointer to path descriptor
         exg   x,y
         bcs   L08BE		names don't match, skip to next
         bsr   L0926		cop this DIR file descriptor to path descriptor
         lda   DIR.FD,x
         sta   PD.FD,y
         ldd   DIR.FD+1,x
         std   PD.FD+1,y
         lbsr  L0A90		check record lock?
         lbra  Sst865		go try again

L08EF    ldx   $08,s
         tsta  			last character?
         bmi   L08FC		yes, skip ahead
         os9   F$PrsNam		parse the name
         leax  ,y		go to the next part of the name
         ldy   $06,s
L08FC    stx   $04,s
         clra  
L08FF    lda   ,s
         leas  $04,s
         pshs  b,a,cc
         IFNE  H6309
         aim   #^BufBusy,PD.SMF,y
         ELSE
         lda   PD.SMF,y
         anda  #^BufBusy
         sta   PD.SMF,y
         ENDC
         puls  pc,u,y,x,b,a,cc

L090D    cmpb  #E$EOF
         bne   L0915
         bsr   L0918
         ldb   #E$PNNF
L0915    coma  
         bra   L08FF

L0918    pshs  d
         lda   $04,s
         cmpa  #PDELIM
         beq   L0940
         ldd   $06,s
         bne   L0940
         bra   L0928		fewer clock cycles
L0926    pshs  d
L0928    stx   $06,s
         lda   PD.FD,y
         sta   PD.DFD,y
         ldd   PD.FD+1,y
         std   PD.DFD+1,y
         IFNE  H6309
         ldq   PD.CP,y
         stq   PD.DCP,y
         ELSE
         ldd   PD.CP,y
         std   PD.DCP,y
         ldd   PD.CP+2,y
         std   PD.DCP+2,y
         ENDC
L0940    puls  pc,b,a

* Move to next directory entry
L0942    ldb   PD.CP+3,y	get current byte pointer
         addb  #DIR.SZ		add in diretory entry size
         stb   PD.CP+3,y	save it back
         bcc   L0957		didn't wrap, skip ahead (need new sector)
         lbsr  L1237		check for sector flush
         inc   PD.CP+2,y
         bne   L0957
         inc   PD.CP+1,y
         bne   L0957
         inc   PD.CP,y
L0957    ldd   #DIR.SZ		get directory entry size
         lbsr  RdLn473		end of directory?
         bcs   L097E		yes, return
         ldd   #DIR.SZ		get directory entry size
         lbsr  L0B0C
         bcs   L097E		yes, return
         lda   PD.SMF,y		get state flags
         bita  #SINBUF		sector in buffer?
         bne   L0977		yes, skip ahead
         lbsr  L1098
         bcs   L097E
         lbsr  L1256
         bcs   L097E
L0977    ldb   PD.CP+3,y	get offset into sector
         lda   PD.BUF,y		get MSB of sector buffer pointer
         tfr   d,x		move it to X
         clrb  			clear error status
L097E    rts   			return

* Get a byte from other task
L097F    pshs  u,x,b
         ldu   <D.Proc
         ldb   P$Task,u
         os9   F$LDABX
         puls  pc,u,x,b

GtDvcNam os9   F$PrsNam		parse the filename
         pshs  x		preserve pointer to name
         bcc   L09B7		no error, check name length & return
         clrb  			clear a counter flag
L0992    pshs  a		preserve last character
         anda  #$7F		clear high bit of last character
         cmpa  #'.		is it current data directory?
         puls  a		restore last character
         bne   L09AD		no, skip ahead
         incb  			flag it's a dir
         leax  1,x
         tsta  			is it the last character of pathname?
         bmi   L09AD		yes, skip ahead
         bsr   L097F		get next character
         cmpb  #$03		third character of DIR?
         bcs   L0992		no, try again
         lda   #PDELIM
         decb  
         leax  -3,x
L09AD    tstb  
         bne   L09B5
L09B0    comb  
         ldb   #E$BPNam
         puls  pc,x

L09B5    leay  ,x
L09B7    cmpb  #DIR.FD-DIR.NM	past maximum size of name?
         bhi   L09B0		yes, return error
         andcc  #^Carry		clear error status
         puls  pc,x		return

* Check for a match of 2 names
* Entry: Y=Pointer to high bit terminated string #1
*        X=Pointer to string #2
*        B=Length of string #1
L09BF    pshs  y,x,b,a
L09C1    lda   ,y+		get a byte from #2
         bmi   L09D1		last one, skip ahead
         decb  			done length?
         beq   L09CE		yes, return no match
         eora  ,x+
         anda  #$DF		match from #1?
         beq   L09C1		yes, check next char
L09CE    comb  			set carry
         puls  pc,y,x,b,a	return

L09D1    decb  			decrement length
         bne   L09CE		not done, return no match
         eora  ,x
         anda  #$5F
         bne   L09CE
         clrb  			clear carry for match
         puls  pc,y,x,b,a

* Check if user can access file/directory
* Entry: A=Attributes of file/directory to check
* Exit : Carry set - User cannot access otherwise clear 
ChkAttrs tfr   a,b		copy attributes
         anda  #(EXEC.!UPDAT.)	keep only file related junk
         andb  #(DIR.!SHARE.)	...and directory related junk
         pshs  x,b,a		preserve
         lbsr  RdFlDscr		get file descriptor
         bcs   L0A0C		error, return
         ldu   PD.BUF,y		get pointer to FD
         ldx   <D.Proc		get current process pointer
         ldd   P$User,x		get user #
         beq   L09F5		super user, skp ahead
         cmpd  FD.OWN,u		match owner of file?
L09F5    puls  a		restore owner attributes
         beq   L09FC		got owner, skip ahead
         lsla  			shift attributes to public area
         lsla  
         lsla  
L09FC    ora   ,s		merge with directory bits
         anda  #^SHARE.		strip off shareable bit
         pshs  a		save it
         ora   #DIR.		set directory bit
         anda  FD.ATT,u		keep only bits we want from attributes
         cmpa  ,s		can he access it?
         beq   L0A15		yes, check directory bits
         ldb   #E$FNA		get error code
L0A0C    leas  $02,s		purge attributes from stack
         coma  			set carry
         puls  pc,x		restore & return

L0A11    ldb   #E$Share,s	get shareable file error
         bra   L0A0C		return

L0A15    ldb   1,s		get directory bits
         orb   FD.ATT,u		mask in with current
         bitb  #SHARE.		shareable bit set?
         beq   L0A28		no, return
         ldx   PD.Exten,y	get path extension
         cmpx  PE.Confl,x	conflicting with anyone?
         bne   L0A11		yes, return error
         lda   #FileLock
         sta   PE.Lock,x
L0A28    puls  pc,x,b,a


L0A2A    pshs  u,y,x
         IFNE  H6309
         clrd
         ELSE
         clra  
         clrb  
         ENDC
         std   PD.CP,y		init current byte pointer
         std   PD.CP+2,y	smaller than STQ
         sta   PD.SSZ,y		init segment size
         std   PD.SSZ+1,y
         ldb   PD.FD,y		get current FD sector #
         ldx   PD.FD+1,y
         pshs  x,b		preserve it
         ldu   PD.DTB,y		get drive table pointer
         ldy   PD.Exten,y	get drive extension pointer
         sty   PE.Confl,y	make it conflict with myself
         leau  DD.SIZ,u		point to local data
         bra   L0A51
* Sort file conflict list???
L0A4F    ldu   V.FileHd-DD.SIZ,u
L0A51    ldx   V.FileHd-DD.SIZ,u	get open file list extension pointer
         beq   L0A7F		none, skip return
         ldx   PE.PDptr,x	get pointer to its path descriptor
         ldd   PD.FD,x		get the file descriptor LSN
         cmpd  ,s		sector lower than mine?
         bcs   L0A4F		yes, skip to next
         bhi   L0A7F		no, return
         ldb   PD.FD+2,x
         cmpb  2,s
         blo   L0A4F		yes, skip to next
         bhi   L0A7F		no, return
         ldx   PD.Exten,x	get the path extension pointer
         IFNE  H6309
         tim   #FileLock,PE.Lock,y	entire file locked?
         ELSE
         ldb   PE.Lock,y
         bitb  #FileLock
         ENDC
         bne   L0A8B		yes, return error
         sty   PE.NxFil,y	terminate list with pointer to myself
         ldd   PE.Confl,x
         std   PE.Confl,y
         sty   PE.Confl,x
         bra   L0A86

L0A7F    ldx   PE.NxFil,u
         stx   PE.NxFil,y
         sty   PE.NxFil,u

L0A86    clrb  
L0A87    leas  $03,s
         puls  pc,u,y,x

L0A8B    comb  
         ldb   #E$Share
         bra   L0A87

L0A90    pshs  u,y,x,b,a
         ldu   PD.DTB,y
         leau  DD.SIZ,u
         ldx   PD.Exten,y
         leay  ,x
         bsr   L0ACF
         bra   L0AA5
L0AA1    ldx   PE.Confl,x
         beq   L0ACA
L0AA5    cmpy  PE.Confl,x
         bne   L0AA1
         ldd   PE.Confl,y
         std   PE.Confl,x
         bra   L0AB2
L0AB0    ldu   PE.NxFil,u
L0AB2    ldd   PE.NxFil,u
         beq   L0ACA		end of list, store end & return
         cmpy  PE.NxFil,u	find myself/
         bne   L0AB0		no, keep looking
         ldx   PE.NxFil,y	get next in line from me
         cmpy  PE.Confl,y	end of conflict list?
         beq   L0AC8		yes, skip ahead
         ldx   PE.Confl,y	get conflicting path extension
         ldd   PE.NxFil,y	get next in line from me
         std   PE.NxFil,x	save it into conflicting extension
L0AC8    stx   PE.NxFil,u	save conflicting extension as next
L0ACA    sty   PE.Confl,y
         puls  pc,u,y,x,b,a

         IFGT  Level-1
L0ACF    lda   #(EofLock!FileLock!RcdLock)	get all types of lockout flags
L0AD1    pshs  u,y,x,b,a
         bita  PE.Lock,y	anything locked?
         beq   L0AE0		no, skip ahead
         coma			invert lock bits
         anda  PE.Lock,y	clear 'em
         sta   PE.Lock,y	save 'em
         bita  #FileLock	is whole file locked?
         bne   L0AFD		yes, return
L0AE0    leau  ,y
L0AE2    ldx   PE.Wait,u
         cmpy  PE.Wait,u
         beq   L0AFA
         stu   PE.Wait,u
         leau  ,x
         lda   PE.Owner,u
         ldb   #S$Wake
         os9   F$Send
         bra   L0AE2
L0AFA    stu   PE.Wait,u
L0AFD    puls  pc,u,y,x,b,a
         ENDC

L0AFF    comb  
         ldb   #E$Share
L0B02    
         IFGT  Level-1
         pshs  y,b,cc
         ldy   PD.Exten,y
         bsr   L0ACF
         puls  pc,y,b,cc
         ELSE
         rts
         ENDC

L0B0C    equ   *
         IFNE  H6309
         tfr   0,x
         ELSE
         ldx   #$0000
         ENDC
         bra   L0B1B

L0B11    ldu   PD.Exten,y
         lda   PE.Req,u
         sta   PE.Lock,u
         bra   L0B1D

* Entry: D=LSW of byte position
*        X=
*        Y=Path descriptor pointer
*        U=
L0B1B    pshs  u,y,x,b,a	preserve regs
L0B1D    ldu   PD.Exten,y	get pointer to path extension
         lda   PE.Lock,u	get lockout status
         sta   PE.Req,u		preserve it
         lda   ,s		get
         bsr   L0B9F		lock the record
         bcc   L0B9D
         ldu   <D.Proc		get current proces pointer
         lda   PE.Owner,x	get owner ID of locked segment
L0B30    os9   F$GProcP		get a pointer to it
         bcs   L0B42		no process left, skip ahead
         lda   P$DeadLk,y	get dominant proc ID
         beq   L0B42		none, skip ahead
         cmpa  P$ID,u		same as current?
         bne   L0B30		no, try again (walks down the process tree)
         ldb   #E$DeadLk	get deadlock error code
         bra   L0B9A		set carry & return

L0B42    lda   PE.Owner,x	get owner of this segment
         sta   P$DeadLk,u	save as the dominant deadlock process
         ldy   4,s		get path descriptor pointer
         IFNE  H6309
         aim   #^BufBusy,PD.SMF,y
         ELSE
         lda   PD.SMF,y
         anda  #^BufBusy
         sta   PD.SMF,y
         ENDC
         ldu   PD.Exten,y	get the path extension
         ldd   PE.Wait,x
         stu   PE.Wait,x
         std   PE.Wait,u
         lbsr  L0C56
         ldx   PE.TmOut,u	get timeout time to wait for release of segment
         os9   F$Sleep		delay a bit
         pshs  x		preserve time slept
         leax  ,u		point X to path extension
         bra   L0B6F		skip ahead

L0B6C    ldx   PE.Wait,x
L0B6F    cmpu  PE.Wait,x
         bne   L0B6C
         ldd   PE.Wait,u
         std   PE.Wait,x
         stu   PE.Wait,u
         puls  x		restore time slept
         ldu   <D.Proc
         clr   P$DeadLk,u
         lbsr  L1053
         bcs   L0B9A
         leax  ,x		X=0?
         bne   L0B11		no,
         ldu   PD.Exten,y	get pointer to extension
         ldx   PE.TmOut,u	get timeout time
         lbeq  L0B11		zero, go try again
         ldb   #E$Lock		get lock error code
L0B9A    coma  			set carry
         stb   $01,s		save error code
L0B9D    puls  pc,u,y,x,b,a

L0B9F    
         IFNE  H6309
         tstd			std -$02,s only to set cc.flags? 4 cycles to 1!
         ELSE
         cmpd  #$0000
         ENDC
         bne   L0BAA
         cmpx  #$0000		the leax may be buggy
         lbeq  L0B02
L0BAA    bsr   L0BC2
         lbcs  L0AFF
         IFGT  Level-1
         pshs  u,y,x
         ldy   PD.Exten,y
         lda   #$01
         lbsr  L0AD1
         ora   PE.Lock,y
         sta   PE.Lock,y
         clrb  
         puls  pc,u,y,x
         ELSE
         clrb
         rts
         ENDC

L0BC2    pshs  u,y,b,a
         leau  ,y
         ldy   PD.Exten,y
         subd  #$0001		NOT a DECD: does't set CC.C
         bcc   L0BD1
         leax  -1,x
L0BD1    addd  PD.CP+2,u
         exg   d,x
         IFNE  H6309
         adcd  PD.CP,u		oughta do same - GH
         ELSE
         adcb  PD.CP+1,u
         adca  PD.CP,u
         ENDC
         bcc   L0BE0
         ldx   #$FFFF
         tfr   x,d
L0BE0    std   PE.HiLck,y
         stx   PE.HiLck+2,y
         cmpd  PD.SIZ,u
         bcs   L0BF8
         bhi   L0BF0
         cmpx  PD.SIZ+2,u
         bcs   L0BF8
L0BF0    equ   *
         IFNE  H6309
         oim   #EofLock,PE.Lock,y
         ELSE
         lda   PE.Lock,y
         ora   #EofLock
         sta   PE.Lock,y
         ENDC
         bra   L0C01
L0BF8    lda   #EofLock
         bita  PE.Lock,y
         beq   L0C01
         lbsr  L0AD1
L0C01    equ   *
         IFNE  H6309
         ldq   PD.CP,u
         stq   PE.LoLck,y
         ELSE
         ldd   PD.CP,u
         std   PE.LoLck,y
         ldd   PD.CP+2,u
         std   PE.LoLck+2,y
         ENDC
         lda   PD.CPR,u
         sta   PE.Owner,y
         leax  ,y
L0C10    cmpy  PE.Confl,x
         beq   L0C54
         ldx   PE.Confl,x
         ldb   PE.Owner,y
         cmpb  PE.Owner,x
         beq   L0C10
         lda   PE.Lock,x
         beq   L0C10
         ora   PE.Lock,y
         bita  #FileLock	either path locked?
         bne   L0C53		yes, skip ahead
         lda   PE.Lock,x
         anda  PE.Lock,y
         bita  #EofLock		both at eof?
         bne   L0C53
         ldd   PE.LoLck,x
         cmpd  PE.HiLck,y
         bhi   L0C10
         bcs   L0C43
         ldd   PE.LoLck+2,x
         cmpd  PE.HiLck+2,y
         bhi   L0C10
         beq   L0C53
L0C43    ldd   PE.HiLck,x
         cmpd  PE.LoLck,y
         bcs   L0C10
         bhi   L0C53
         ldd   PE.HiLck+2,x
         cmpd  PE.LoLck+2,y
         bcs   L0C10
L0C53    comb  
L0C54    puls  pc,u,y,b,a

L0C56    pshs  y,x,b,a
         ldx   <D.Proc
         lda   P$IOQN,x		get I/O queue next ptr
         beq   L0C6C		none, exit
         clr   P$IOQN,x		set to none
         ldb   #S$Wake
         os9   F$Send		wake up
         os9   F$GProcP		get process descriptor pointer
         clr   P$IOQP,y		clear its I/O queue previous pointer
L0C6C    clrb  
         puls  pc,y,x,b,a

L0C6F    pshs  u,x
L0C71    bsr   L0CD1
         bne   L0C81
         cmpx  PD.SSZ+1,y
         bcs   L0CC8
         bne   L0C81
         lda   PD.SIZ+3,y
         beq   L0CC8
L0C81    lbsr  RdFlDscr
         bcs   L0CC5
         ldx   PD.CP,y
         ldu   PD.CP+2,y	grab current position
         pshs  u,x		save it
         IFNE  H6309
         ldq   PD.SIZ,y		go to the end of the file
         stq   PD.CP,y
         ELSE
         ldd   PD.SIZ,y
         std   PD.CP,y
         ldd   PD.SIZ+2,y
         std   PD.CP+2,y
         ENDC
         lbsr  L10B2		search ???
         puls  u,x		restore current position
         stx   PD.CP,y		and save back in PD again
         stu   PD.CP+2,y
         bcc   L0CC8
         cmpb  #E$NES		non-existing segment error?
         bne   L0CC5
         bsr   L0CD1
         bne   L0CB1
         tst   PD.SIZ+3,y
         beq   L0CB4
         leax  1,x
         bne   L0CB4
L0CB1    ldx   #$FFFF
L0CB4    tfr   x,d
         tsta  
         bne   L0CC1
         cmpb  PD.SAS,y
         bcc   L0CC1
         ldb   PD.SAS,y
L0CC1    bsr   L0D07		go do something...
         bcc   L0C71
L0CC5    coma  
         puls  pc,u,x

L0CC8    lbsr  L1098
         bcs   L0CC5
         bsr   L0CDF
         puls  pc,u,x

L0CD1    ldd   PD.SIZ+1,y
         subd  PD.SBL+1,y
         tfr   d,x
         ldb   PD.SIZ,y
         sbcb  PD.SBL,y
         rts   

L0CDF    clra  
         ldb   #$02
         pshs  u,x
         ldu   PD.Exten,y
         bra   L0CFD

L0CE9    ldu   PE.PDptr,u
         ldx   PD.SIZ,y		don't do LDQ/STQ, as A and B are used below
         stx   PD.SIZ,u
         ldx   PD.SIZ+2,y
         stx   PD.SIZ+2,u
         bitb  PD.MOD,y
         beq   L0CFA
         inca  
L0CFA    ldu   PD.Exten,u
L0CFD    ldu   PE.Confl,u
         cmpy  PE.PDptr,u
         bne   L0CE9
         tsta  
         puls  pc,u,x

* Update a file descriptor
L0D07    pshs  u,x
         lbsr  FatScan		search and allocate D sectors
         bcs   L0D4E		exit on error
         lbsr  RdFlDscr		read a FD from disk
         bcs   L0D4E		exit on error
         ldu   PD.BUF,y		grab the buffer pointer
         IFNE  H6309
         clrd  
         tfr   d,w
         stq   FD.SIZ,u		set the file size to zero
         ELSE
         clra  
         clrb  
         std   FD.SIZ,u
         std   FD.SIZ+2,u
         ENDC
         leax  FD.SEG,u		point to the segment size
         ldd   FDSL.B,x		grab the segment size
         beq   L0D96		exit if zero
         ldd   PD.BUF,y		grab the buffer pointer
         inca  			point to the end of it
         pshs  d		save on-stack
         bra   L0D36		skip ahead

L0D29    clrb  
         ldd   -$02,x		grab previous segment sector size
         beq   L0D4A		zero: exit
* Add in checks to see if this segment's LSN is $00000000?
         addd  FD.SIZ+1,u	add sector size to total file size
         std   FD.SIZ+1,u
         bcc   L0D36
         inc   FD.SIZ,u		increment file size if 24-bit overflow
L0D36    leax  FDSL.S,x		go up one segment in the FD
         cmpx  ,s		done yet?
         bcs   L0D29		no, continue
* or do check for last segment LSN0, size 1 here?
         lbsr  ClrFBits		delete a segment?
         IFNE  H6309
         clrd
         ELSE
         clra  
         clrb  
         ENDC
         sta   PD.SSZ,y		segment size is zero
         std   PD.SSZ+1,y
         comb  
         ldb   #E$SLF		segment list full error

L0D4A    leas  2,s		remove pointer to end of PD.BUF from the stack
         leax  -FDSL.S,x	back up a segment
L0D4E    bcs   L0DB3
         ldd   -4,x
         addd  -2,x
         pshs  b,a
         ldb   -5,x
         adcb  #$00
         cmpb  PD.SBP,y
         puls  d
         bne   L0D96
         cmpd  PD.SBP+1,y
         bne   L0D96
         ldu   PD.DTB,y
         ldd   DD.BIT,u
         ldu   PD.BUF,y
         subd  #1
         coma  
         comb			comd is prolly wrong reg order!
         pshs  d
         ldd   -$05,x
         IFNE  H6309
         eord  PD.SBP,y
         lsrd  
         lsrd  
         lsrd  
         andd  ,s++
         tstd  
         ELSE
         eora  PD.SBP,y
         eorb  PD.SBP+1,y
         lsra
         rorb
         lsra
         rorb
         lsra
         rorb
         anda  ,s+
         andb  ,s+
         cmpd  #$0000
         ENDC
         bne   L0D96
         ldd   -2,x
         addd  PD.SSZ+1,y
         bcs   L0D96
         std   -2,x
         bra   L0DA5

L0D96    ldd   PD.SBP,y
         std   ,x
         lda   PD.SBP+2,y
         sta   2,x
         ldd   PD.SSZ+1,y
         std   3,x
L0DA5    ldd   FD.SIZ+1,u
         addd  PD.SSZ+1,y
         std   FD.SIZ+1,u
         bcc   L0DB0
         inc   FD.SIZ,u

L0DB0    lbsr  L11FD		flush a FD sector tothe disk
L0DB3    puls  pc,u,x

* Search the allocation bitmap for a number of free sectors
* Entry: D = number of sectors to look for
*        Y = PD pointer
* 0,S  = number of clusters to allocate
* 2,S  = DD.BIT  number of sectors per cluster
* 4,S  = DD.MAP  number of bytes in the allocation bitmap
* 6,S  = V.MapSCT lowest reasonable bitmap sector number (current bitmap sect)
* 7,S  = sector number of the largest contiguous free bits found
* 8,S  = number of contiguous free bits found
* 10,s = bit offset into the sector of the found contiguous bits
* 10,s = also  DD.BIT  number of sectors per cluster
* 12,S = number of sectors to search for  (D from the calling routine)
* 16,S = PD pointer (Y from the calling routine)
FatScan  pshs  u,y,x,b,a
         ldb   #$0C
L0DB9    clr   ,-s		reserve 12 bytes of junk on-stack
         decb  
         bne   L0DB9
         ldx   PD.DTB,y
         ldd   DD.MAP,x		number of bytes in allocation bitmap
         std   4,s
         ldd   DD.BIT,x		number of sectors per cluster
         std   2,s
         std   10,s
         ldx   PD.DEV,y		get pointer to device table entry
         ldx   V$DESC,x		point to descriptor
         leax  M$DTyp,x		get device type
         subd  #1
         addb  IT.SAS-M$DTyp,x	add in one sector allocation size
         adca  #0		make it 16-bit
         bra   L0DDD		default to greater of SAS or DD.BIT

L0DDB    equ   *
         IFNE  H6309
         lsrd  			shift D to the right
         ELSE
         lsra
         rorb
         ENDC
L0DDD    lsr   $0A,s		shift DD.BIT to the right
         ror   $0B,s
         bcc   L0DDB		loop until carry is set
         std   ,s		D = number of clusters to allocate
         ldd   2,s		get old DD.BIT
         std   $0A,s		save on-stack again
         subd  #$0001
         addd  $0C,s		add in to the number of sectors we're asked to
         bcc   L0DF7		allocate
         ldd   #$FFFF		if larger than 64K sectors, default to 64K
         bra   L0DF7		skip ahead

L0DF5    equ   *
         IFNE  H6309
         lsrd  			shift number of sectors to allocate
         ELSE
         lsra
         rorb
         ENDC
L0DF7    lsr   $0A,s
         ror   $0B,s
         bcc   L0DF5		loop, and continue
* ATD: remove this code for HD's, to allow >2048 cluster segments???
* It may be easier to read in the FD, and COMPACT it by looking for
* LSN+SIZE=next segment LSN.  But that would take 48*(30?) clock cycles,
* which is a lot of time... but maybe not compared to F$All/F$Sch, and
* the sector read/writes...
         cmpa  #8		at least 256*8 bits to allocate?
         bcs   L0E04		number of clusters is OK, skip ahead
         ldd   #$0800		force one sector of clusters max. to be allocated
L0E04    std   $0C,s		save as the number of clusters to allocate
         lbsr  L1036		make us the current user of the allocation bitmap
         lbcs  L0EF2		exit on error
         ldx   PD.DTB,y		get drive table
         ldd   V.DiskID,x	and old disk ID
         cmpd  DD.DSK,x		check against the current disk ID
         bne   L0E26		if not the same, make us the current disk ID
         lda   V.BMapSz,x	same allocation bitmap size?
         cmpa  DD.MAP,x
         bne   L0E26		no, skip ahead
         ldb   V.MapSct,x	another check
         cmpb  DD.MAP,x
         bcs   L0E34

L0E26    ldd   DD.DSK,x		get current disk ID
         std   V.DiskID,x	make us the disk to use
         lda   DD.MAP,x		grab number of sectors in allocation bitmap
         sta   V.BMapSz,x	save for later
         clrb  
         stb   V.MapSct,x	make this zero for now
L0E34    incb  			account for LSN0
         stb   6,s		lowest reasonable bitmap sector number
* ATD: Is this line necessary?  All calls to L0E34 set up X already
         ldx   PD.DTB,y		get drive table pointer again
         cmpb  V.ResBit,x	check B against reserved bitmap sector
         beq   L0E70		same, skip ahead
         lbsr  L1091		go read in a bitmap sector
         lbcs  L0EF2
         ldb   6,s		grab copy of V.MapSCT again
         cmpb  4,s		check against number of sectors in allocation bitmap
         bls   L0E51		lower, continue
         clra  			if at end of the allocation bitmap,
         ldb   5,s		don't search it all, but just to the end of the
         bra   L0E54		last sector in the allocation bitmap

* ATD: This the routine that we would fix to cache a compressed version
* of the allocation bitmap.  i.e. largest group of contiguous free sectors,
* where 255 == 256 by definition. At 1 byte/sector, max. 256 sectors in the
* allocation bitmap, max. 256 bytes.  The search should be a LOT faster then,
* as we'll only have to search memory and not read in all those sectors.
* If we're really daring, we could build the new FD without reading the
* allocation bitmap _at_all_, and just use a 'best-fit' algorithm on the
* cached version, and update the bitmap later.
* RBF doesn't do any other search bit calls, so this is the routine.
L0E51    ldd   #$0100
L0E54    ldx   PD.BUF,y		where to start searching
         leau  d,x		where to stop searching
         ldy   $0C,s		number of bits to find
* ATD: force it to be less than 1 sector here...
         IFNE  H6309
         clrd  			at starting bit number 0
         ELSE
         clra  
         clrb  
         ENDC
         os9   F$SchBit
         bcc   L0E9D		found bits
         cmpy  8,s		check number of found bits against our maximum
         bls   L0E70		smaller, skip ahead
         sty   8,s		save as new maximum
         std   $0A,s		save starting bit number
         lda   6,s		grab current sector
         sta   7,s		save for later
L0E70    ldy   <$10,s		grab old PD pointer
         ldb   6,s		grab current bitmap sector number
         cmpb  4,s		check against highest sector number of bitmap
         bcs   L0E81		we're OK, skip ahead
         bhi   L0E80		we're too high, skip ahead
         tst   5,s		check bytes in the sector
         bne   L0E81		not zero: skip ahead
L0E80    clrb  
L0E81    ldx   PD.DTB,y		get drive table pointer again
         cmpb  V.MapSct,x	check against lowest reasonable bitmap sector
         bne   L0E34		ifnot the same, continue

         ldb   7,s		grab sector number of largest block found
         beq   L0EF0		zero, exit with E$Full error
         cmpb  6,s		is it the current sector?
         beq   L0E96		yes, skip ahead
         stb   6,s		make it the current sector
         lbsr  L1091		go read the sector in from disk

L0E96    ldx   PD.BUF,y		point to the sector in the buffer
         ldd   $0A,s		grab starting bit number
         ldy   8,s		and number of bits to allocate
L0E9D    std   $0A,s		save starting bit number
         sty   8,s		and number of bits to allocate
         os9   F$AllBit		go allocate the bits
         ldy   $10,s		grab the PD pointer again
         ldb   $06,s		and the sector number
         lbsr  L1069		write it out to disk
         bcs   L0EF2		exit on error
* ATD: add check for segments left to allocate, if we've allocated
* one entire sector's worth???
* What about special-purpose code to read the allocation bitmap byte by byte
* and do it that way?  I dunno...
* Have some routine inside L0DB5 call another routine which allocates segments
* one sector at a time... have a check: got one sector?
* ATD: We'll probably have to add in allocation bitmap caching for this
* to work properly....
         ldx   PD.DTB,y		drive table pointer
         lda   6,s		current sector
         deca  			decreemnt
         sta   V.MapSct,x	AHA! Last searched sector for later use
         clrb  
         lsla			move high bit of A into CC.C
         rolb			move CC.C into B
         lsla			etc.
         rolb			cannot do a ROLD, as that would be LSB, ROLA
         lsla			i.e. move the 3 high bits of A into low bits of B
         rolb			and shift A by 3
         stb   PD.SBP,y		save segment beginning physical sector number
         ora   $0A,s		OR in with the start bit number
         ldb   $0B,s		grab LSB of starting bit number
         ldx   8,s		and number of free sectors found
* ATD: Is this next line really necessary?
         ldy   $10,s		get PD pointer
         std   PD.SBP+1,y	save low 2 bytes of segment beginning physical SN
         stx   PD.SSZ+1,y	and segment size in clusters
         ldd   2,s		grab number of sectors per cluster
         bra   L0EE6

L0ED7    lsl   PD.SBP+2,y	shift physical sector numberup
         rol   PD.SBP+1,y	to LSN, to account for cluster size
         rol   PD.SBP,y
         lsl   PD.SSZ+2,y
         rol   PD.SSZ+1,y	shift segment cluster size to sector size
L0EE6   
         IFNE  H6309
         lsrd  
         ELSE
         lsra
         rorb
         ENDC
         bcc   L0ED7

         clrb  			no errors
         ldd   PD.SSZ+1,y	number of sectors allocated
         bra   L0EFA		and return to the user

L0EF0    ldb   #E$Full
L0EF2    ldy   $10,s		get old Y off of the stack
         lbsr  L1070		return allocation bitmap?
         coma  
L0EFA    leas  $0E,s		skip 12-byte buffer, and D
         puls  pc,u,y,x

* Set the size of a file to PD.SIZ, where PD.SIZ is SMALLER than the
* current size of the file.
L0EFE    clra               clear the carry
* This code ensures that directories are never shrunk in size.
         lda   PD.MOD,y		access mode
         bita  #DIR.		directory?
         bne   L0F6F		yes (bit set), exit immediately
         IFNE  H6309
         ldq   PD.SIZ,y		grab size of the file
         stq   PD.CP,y		make it the current position
         ELSE
         ldd   PD.SIZ,y
         std   PD.CP,y
         ldd   PD.SIZ+2,y
         std   PD.CP+2,y
         ENDC
         ldd   #$FFFF
         tfr   d,x
         lbsr  L0B1B
         bcs   L0F6E
         lbsr  L0CDF
         bne   L0F6F		exit
         lbsr  L10B2		find a segment
         bcc   L0F26
         cmpb  #E$NES		non-existing segment error
         bra   L0F67

L0F26    ldd   PD.SBL+1,y	not quite sure what's going on here...
         subd  PD.CP+1,y
         addd  PD.SSZ+1,y
         tst   PD.CP+3,y	on a sector boundary?
         beq   L0F35		yes, skip ahead
         IFNE  H6309
         decd			ok here, carry NOT used below
         ELSE
         subd  #$0001
         ENDC
L0F35    pshs  d
         ldu   PD.DTB,y		number of sectors per cluster
         ldd   DD.BIT,u
         IFNE  H6309
         decd  
         comd  
         andd  ,s++
         ELSE
         subd  #$0001
         coma
         comb
         anda  ,s+
         andb  ,s+
         ENDC
         ldu   PD.SSZ+1,y
         std   PD.SSZ+1,y
         beq   L0F69
         tfr   u,d
         subd  PD.SSZ+1,y
         pshs  x,b,a
         addd  PD.SBP+1,y
         std   PD.SBP+1,y
         bcc   L0F5F
         inc   PD.SBP,y
L0F5F    bsr   ClrFBits		delete a segment
         bcc   L0F70
         leas  4,s
         cmpb  #E$IBA		illegal block address

L0F67    bne   L0F6E
L0F69    lbsr  RdFlDscr
         bcc   L0F79
L0F6E    coma  
L0F6F    rts   

L0F70    lbsr  RdFlDscr
         bcs   L0FC9
         puls  x,b,a
         std   FDSL.B,x
L0F79    ldu   PD.BUF,y
         IFNE  H6309
         ldq   PD.SIZ,y		grab file size from the PD
         stq   FD.SIZ,u		save in the FD file size
         ELSE
         ldd   PD.SIZ,y
         std   FD.SIZ,u
         ldd   PD.SIZ+2,y
         std   FD.SIZ+2,u
         ENDC
         tfr   x,d
         clrb  
         inca  
         leax  FDSL.S,x		go to the next segment
         pshs  x,b,a
         bra   L0FB4
L0F8E    ldd   -2,x
         beq   L0FC1
         std   PD.SSZ+1,y
         ldd   -FDSL.S,x	grab stuff from the last segment
         std   PD.SBP,y
         lda   -FDSL.B,x
         sta   PD.SBP+2,y	save sector beginning physical sector number
         bsr   ClrFBits		delete a segment
         bcs   L0FC9
         stx   2,s
         lbsr  RdFlDscr
         bcs   L0FC9
         ldx   2,s
         IFNE  H6309
         clrd  
         ELSE
         clra  
         clrb  
         ENDC
         std   -$05,x		clear out the segment
         sta   -$03,x
         std   -$02,x
L0FB4    lbsr  L11FD
         bcs   L0FC9
         ldx   2,s
         leax  FDSL.S,x		go to the next segment
         cmpx  ,s
         bcs   L0F8E		if not done, do another
L0FC1    equ   *
         IFNE  H6309
         clrd  
         ELSE
         clra  
         clrb  
         ENDC
         sta   PD.SSZ,y
         std   PD.SSZ+1,y	segment size is zero
L0FC9    leas  4,s
         rts   

* de-allocate a segment
ClrFBits pshs  u,y,x,a		get device table pointer
         ldx   PD.DTB,y

* ATD: Added next few lines to ENSURE that LSN0 and the allocation bitmap
* are NEVER marked as de-allocated in the allocation bitmap
*         ldd   PD.SBP,y     grab beginning segment physical LSN
*         bne   L0FD0        skip next code if too high
*         ldd   DD.MAP,x     get number of bytes in allocation bitmap
*         addd  #$01FF       add 1 for LSN0, round up a sector: A=lowest LSN
*         cmpa  PD.SBP+2,y   check LSN0 + DD.MAP against LSN to deallocate
*         blo   L0FD0        if PD.SBP is higher than LSN0 + DD.MAP, allow it
*         ldb   #E$IBA       illegal block address: can't deallocate LSN0
*         bra   L1033        or the allocation bitmap sectors from the bitmap!

         ldd   DD.BIT,x
         IFNE  H6309
         decd
         ELSE
         subd  #$0001
         ENDC
         addd  PD.SBP+1,y
         std   PD.SBP+1,y
         ldd   DD.BIT,x
         bcc   L0FF4
         inc   PD.SBP,y
         bra   L0FF4

L0FE5    lsr   PD.SBP,y		convert sector number to cluster number
         ror   PD.SBP+1,y
         ror   PD.SBP+2,y
         lsr   PD.SSZ+1,y
         ror   PD.SSZ+2,y
L0FF4    equ   *
         IFNE  H6309
         lsrd  
         ELSE
         lsra
         rorb
         ENDC
         bcc   L0FE5

         clrb  
         ldd   PD.SSZ+1,y
         beq   L1034
         ldd   PD.SBP,y
         IFNE  H6309
         lsrd  
         lsrd  
         lsrd  			get cluster byte number into D
         ELSE
         lsra
         rorb
         lsra
         rorb
         lsra
         rorb
         ENDC
         tfr   b,a
         ldb   #E$IBA
         cmpa  DD.MAP,x		is the LSN too high: mapped outside of the bitmap?
         bhi   L1033		yes, error out
         inca  
         sta   ,s
L1012    bsr   L1036		flush the sector, and OWN the bitmap
         bcs   L1012
         ldb   ,s		grab the sector number
         bsr   L1091		go read a sector fro the allocation bitmap
         bcs   L1033
         ldx   PD.BUF,y		where to start
         ldd   PD.SBP+1,y	bit offset to delete
* ATD: keep deleting sectors until we're done!
         anda  #$07		make sure it's within the current sector
* ATD: fix segment sizes!
         ldy   PD.SSZ+1,y	number of clusters to deallocate
         os9   F$DelBit		go delete them (no error possible)
         ldy   3,s
         ldb   ,s		grab bitmap sector number again
         bsr   L1069		go write it out
         bcc   L1034		xit on error
L1033    coma  
L1034    puls  pc,u,y,x,a

L1036    lbsr  L1237		flush the sector to disk
         bra   L1043		skip ahead

L103B    lbsr  L0C56		wakeup the process
         os9   F$IOQu		queue the process
         bsr   L1053		check for process wakeup
L1043    bcs   L1052		error, return
         ldx   PD.DTB,y		get drive table ptr
         lda   V.BMB,x		bitmap sector
         bne   L103B		if set, continue
         lda   PD.CPR,y		get our process number
         sta   V.BMB,x		make us the current user of the bitmap
L1052    rts   

* Wait for process to wakeup
L1053    ldu   <D.Proc		get current process pointer
         ldb   P$Signal,u	get pending signal
         cmpb  #S$Wake		is it what we're looking for?
         bls   L1060		yes, skip ahead
         cmpb  #S$Intrpt	is it a keyboard interrupt/
         bls   L1067		no, return error [B]=Error code
L1060    clra  			clear error status
         IFNE  H6309
         tim   #Condem,P$State,u	is process dead?
         ELSE
         lda   P$State,u
         bita  #Condem         
         ENDC
         beq   L1068		no, skip ahead
L1067    coma  			flag error
L1068    rts   			return

* Write a file allocation bitmap sector
* Entry: B=Logical sector #
L1069    clra  			clear MSB of LSW to logical sector #
         tfr   d,x		move it to proper register
         clrb  			clear MSB of logical sector #
         lbsr  L1207		flush the sector to drive
L1070    pshs  cc		preserve error status from write
         ldx   PD.DTB,y		get drive table pointer
         lda   PD.CPR,y		get the current process using it
         cmpa  V.BMB,x		same as process using the bit-map sector?
         bne   L108F		no, return
         clr   V.BMB,x		clear the use flag
         ldx   <D.Proc		get current process pointer
         lda   P$IOQN,x		get next process in line for sector
         beq   L108F		none, return
         lbsr  L0C56		wake up the process
         ldx   #1		sleep for balance of tick
         os9   F$Sleep
L108F    puls  pc,cc		restore error status & return

* Read a sector from file allocation bit map
* Entry: B=Logical sector #
L1091    clra  			clear MSB of LSW to logical sector #
         tfr   d,x		move to proper register
         clrb  			clear MSB of logical sector #
         lbra  L113A		go read the sector

* Entry: Y=Path descriptor pointer
L1098    ldd   PD.CP+1,y
         subd  PD.SBL+1,y
         tfr   d,x
         ldb   PD.CP,y
         sbcb  PD.SBL,y
         cmpb  PD.SSZ,y
         bcs   L10B0
         bhi   L10B2		yes, scan the segment list
         cmpx  PD.SSZ+1,y
         bcc   L10B2
L10B0    clrb  
L10B1    rts   

* Scan file segment list to get proper segment based on current byte position
* in the file.  Once found it will be placed in the path descriptor
* Entry: None
L10B2    pshs  u		preserve
         bsr   RdFlDscr		get the file descriptor
         bcs   L110E		error, return
         IFNE  H6309		init the start point of search in path descriptor
         clrd  
         ELSE
         clra  
         clrb  
         ENDC
         std   PD.SBL,y
         stb   PD.SBL+2,y
         ldu   PD.BUF,y		get sector buffer pointer
         leax  FD.SEG,u		point to segment list
         lda   PD.BUF,y		get MSB of sector buffer pointer
         ldb   #$FC		get size of segment table
         pshs  b,a		save as table end pointer
* Scan segment list for the proper segment
L10CB    ldd   FDSL.B,x		get segment size in sectors
         beq   L10F0		last one, exit with non existing segment error
         addd  PD.SBL+1,y	add to segment start LSN
         tfr   d,u		copy it
         ldb   PD.SBL,y
         adcb  #0
         cmpb  PD.CP,y		this the segment we want?
         bhi   L10FD		yes, move the segment start & size to descriptor
         bne   L10E4		no, save this segment & keep looking
         cmpu  PD.CP+1,y
         bhi   L10FD
L10E4    stb   PD.SBL,y
         stu   PD.SBL+1,y
         leax  FDSL.S,x		move to next segment
         cmpx  ,s		done?
         bcs   L10CB		no, keep going

* Return Non-Existing segment error
L10F0    equ   *
         IFNE  H6309
         clrd
         ELSE
         clra  
         clrb  
         ENDC
         sta   PD.SSZ,y		zero out the segment
         std   PD.SSZ+1,y
         comb  			set the carry
         ldb   #E$NES		non-existing segment
         bra   L110C		return

* Move segment to path descriptor
L10FD    ldd   FDSL.A,x		get start physical sector #
         std   PD.SBP,y		put it in path descriptor
         lda   FDSL.A+2,x
         sta   PD.SBP+2,y
         ldd   FDSL.B,x		get segment size
         std   PD.SSZ+1,y	put it in path descriptor
L110C    leas  2,s
L110E    puls  pc,u

* Read LSN0 from drive
* Entry: Y=Path descriptor pointer
L1110    pshs  x,b		preserve regs used
         lbsr  L1237		flush sector buffer
         bcs   L111F		error, return
         clrb  			get LSN
         ldx   #$0000
         bsr   L113A		read the sector
         bcc   L1121		no error, return
L111F    stb   ,s		save error code
L1121    puls  pc,x,b		restore & return

* Read a file descriptor from disk
* Entry: Y=Path descriptor pointer
RdFlDscr 
         IFNE  H6309
         tim   #FDBUF,PD.SMF,y	FD already here?
         ELSE
         ldb   PD.SMF,y
         bitb  #FDBUF 
         ENDC
         bne   L10B0		yes, return no error
         lbsr  L1237		flush any sector here
         bcs   L10B1		error, return
         IFNE  H6309
         oim   #FDBUF,PD.SMF,y
         ELSE
         lda   PD.SMF,y
         ora   #FDBUF
         sta   PD.SMF,y
         ENDC
         ldb   PD.FD,y		get MSB of logical sector
         ldx   PD.FD+1,y	get LSW of logical sector
L113A    lda   #D$READ		get read offset
* Send command to device driver
* Entry: A=Driver Command offset
*        B=MSB of logical sector #
*        X=LSW of logical sector #
*        Y=Path descriptor pointer
L113C    pshs  u,y,x,b,a	preserve it all
         IFNE  H6309
         oim   #InDriver,PD.SMF,y	flag we're in ddriver
         ELSE
         lda   PD.SMF,y
         ora   #InDriver
         sta   PD.SMF,y
         ENDC
         ldx   <D.Proc		get current process pointer
         lda   P$Prior,x	get its priority
         tfr   a,b		copy it
         addb  #3		add 3 to it
         bcc   L1150		didn't wrap, skip ahead
         ldb   #$FF		force it to max
L1150    stb   P$Prior,x	save priority
         stb   P$Age,x		asage too
         ldx   PD.Exten,y	get path extension pointer
         sta   PE.Prior,x	save original priority there
         ldu   PD.DEV,y		get device table pointer
         ldu   V$STAT,u		get static mem pointer
         bra   L1166		go execute driver
* Wait for device
L1160    lbsr  L0C56		wakeup waiting process
         os9   F$IOQu		queue device
* Device ready, send command
L1166    lda   V.BUSY,u		driver already busy?
         bne   L1160		yes, queue it
         lda   PD.CPR,y		get current process #
         sta   V.BUSY,u		save it as busy
         ldd   ,s		get command & logical sector from stack
         ldx   2,s
         pshs  u		save static mem
         bsr   L11EB		send it to driver
         puls  u		restore static mem
         ldy   4,s		get path descriptor pointer
         pshs  cc		preserve driver error status
         bcc   L1181		no error, skip ahead
         stb   2,s		save driver's error code
L1181    equ   *
         IFNE  H6309
         aim   #^InDriver,PD.SMF,y	clear in driver flag
         ELSE
         lda   PD.SMF,y
         anda  #^InDriver
         sta   PD.SMF,y
         ENDC
         clr   V.BUSY,u
         ldx   PD.Exten,y
         lda   PE.Prior,x
         ldx   <D.Proc
         sta   P$Prior,x
******
* this code is in v31 only
         lda   ,s		get driver error status
         bita  #Carry		was there an error?
         bne   L11CB		yes, return with it
         lda   1,s		get the driver command
         cmpa  #D$WRIT		was it write sector?
         bne   L11CB		no, return
         pshs  u,y,x		preserve regs
         ldy   PD.Exten,y
         leau  ,y
L11A7    ldx   PE.Confl,u
         cmpy  PE.Confl,u
         beq   L11C9
         leau  ,x

* Check for signal on data write
         lda   PE.SigID,u	anything to send signal to?
         beq   L11A7		no, skip to next in chain
         ldx   <D.Proc		get current process
         cmpa  P$ID,x
         beq   L11A7
         clr   PE.SigID,u
         ldb   PE.SigSg,u
         os9   F$Send
         bra   L11A7

L11C9    puls  u,y,x
L11CB    lda   P$IOQN,x		any process waiting?
         beq   L11E9		no, return
         lda   $01,y
         bita  #$04
         bne   L11E9
         ldx   PD.DTB,y		get driver table pointer
         lda   PD.CPR,y		get current process ID
         cmpa  V.BMB,x		same as bitmap use process?
         beq   L11E9		yes, return
         lbsr  L0C56
         ldx   #1		sleep for balance of tick
         os9   F$Sleep
L11E9    puls  pc,u,y,x,b,a,cc	restore & return

* Execute device driver
* Entry: A=Driver command offset
*        B=MSB of logical sector #
*        X=LSW of logical sector #
*        Y=Path descriptor pointer
*        U=Static memory pointer
L11EB    pshs  pc,x,b,a
         ldx   PD.DEV,y
         ldd   V$DRIV,x
         ldx   V$DRIV,x
         addd  M$Exec,x
         addb  ,s		
         adca  #$00
         std   $04,s
         puls  pc,x,b,a

* Write file descriptor to disk
* Entry: Y=Path descriptor pointer
L11FD    ldb   PD.FD,y		get MSB of LSN
         ldx   PD.FD+1,y	get LSW of LSn
         bra   L1207		send it to disk


* Flush sector buffer to disk
* Entry: Y=Path descriptor pointer
L1205    bsr   L1220		calulate LSN
L1207    lda   #D$WRIT		get driver write offset
         pshs  x,b,a		preserve that & LSN
         ldd   PD.DSK,y		get disk ID of this sector
         beq   L1216		nothing, send it to driver
         ldx   PD.DTB,y		get drive table pointer
         cmpd  DD.DSK,x		match ID from drive?
L1216    puls  x,b,a		restore regs
         lbeq  L113C		ID matches, send data to driver
         comb  			set carry
         ldb   #E$DIDC		get ID change error code
         rts   			return

* Calculate logical sector # of current sector in buffer
* Exit : B=MSB of logical sector #
*        X=LSW of logical sector #
L1220    ldd   PD.CP+1,y	get current logical sector loaded
         subd  PD.SBL+1,y	subtract it from segment list LSN
         tfr   d,x		copy answer
         ldb   PD.CP,y		get MSB of byte position
         sbcb  PD.SBL,y		subtract it from segment start
         exg   d,x
         addd  PD.SBP+1,y	add in physical segment sector #
         exg   d,x
         adcb  PD.SBP,y		now the MSB
         rts   			return

* Check if sector buffer needs to be flushed to disk
* Entry: Y=Path descriptor pointer
L1237    clrb  			clear carry
         pshs  u,x		preserve regs
         ldb   PD.SMF,y		get state flags
         andb  #(BufBusy!FDBUF!SINBUF)	aynything in buffer?
         beq   L1254		no, return
         tfr   b,a		duplicate flags
         eorb  PD.SMF,y		clear them
         stb   PD.SMF,y		save 'em
         andb  #BUFMOD		has buffer been modified?
         beq   L1254		no, return
         eorb  PD.SMF,y		clear that bit
         stb   PD.SMF,y		save it
         bita  #SINBUF		is there even a sector in buffer?
         beq   L1254		no, return
         bsr   L1205		flush the sector to drive
L1254    puls  pc,u,x		restore & return

L1256    pshs  u,x
         lbsr  L1098
         bcs   L12C6
         bsr   L1237
         bcs   L12C6
L1261    ldb   PD.CP,y
         ldu   PD.CP+1,y
         leax  ,y
         ldy   PD.Exten,y
L126B    ldx   PD.Exten,x
         cmpy  PE.Confl,x
         beq   L12B5
         ldx   PE.Confl,x
         ldx   PE.PDptr,x
         cmpu  PD.CP+1,x
         bne   L126B
         cmpb  PD.CP,x
         bne   L126B
         lda   PD.SMF,x
         bita  #SINBUF
         beq   L126B
         bita  #InDriver
         bne   L128E
         bita  #BufBusy
         beq   L12A0
L128E    lda   PD.CPR,x
         ldy   PE.PDptr,y
         lbsr  L0C56
         os9   F$IOQu
         lbsr  L1053
         bcc   L1261
         puls  u,x,pc

L12A0    ldy   PE.PDptr,y
         ldd   PD.BUF,x
         ldu   PD.BUF,y
         std   PD.BUF,y
         stu   PD.BUF,x
         lda   PD.SMF,x   \ careful, don't use oim here
         ora   #BufBusy   >takes state from x and
         sta   PD.SMF,y   / stores to y, is infamous "lha" bug
         clr   PD.SMF,x
         puls  pc,u,x

L12B5    ldy   PE.PDptr,y
         lbsr  L1220
         lbsr  L113A
         bcs   L12C6
         IFNE  H6309
         oim   #(BufBusy!SINBUF),PD.SMF,y
         ELSE
         pshs  a
         lda   PD.SMF,y
         ora   #(BufBusy!SINBUF)
         sta   PD.SMF,y
         puls  a
         ENDC
L12C6    puls  pc,u,x

         emod  
eom      equ   *
         end

