*************************
*   HappyENV-Handler	*
*     0.8 31.8.96	*
*  (C) Martin Gierich	*
*************************


; Do not use this source code or parts of it in other programs !
; See documentation about Copyright&Disclaimer



;DEBUG		= 1
;VOLUME		= 1
;VERBOSE	= 1
AUTOCOPY	= 1

	INCDIR	source:stripinc/
	INCLUDE	exec/exec_lib.i
	INCLUDE	dos/dos_lib.i
	INCLUDE	dos/dosextens.i
	INCLUDE	dos/filehandler.i
	INCLUDE	dos/notify.i
	INCLUDE debug.i

CALL	MACRO
	jsr	_LVO\1(a6)
	ENDM

mn_Node		= 0
lib_Version	= 20
_LVOToUpper	= -174
DOS_TRUE	= -1
DOS_FALSE	= 0
MEMF_CLEAR	= $10000
MAXPATH		= 120
MAXNAME		= 32


* notify list node structure
		RSRESET
myn_Link	RS.L	1
myn_Request	RS.L	1	notify-request
myn_Key		RS.L	1	pointer to file
myn_Name	RS.B	MAXPATH
myn_SIZEOF	RS.W	0

* lock structure for Lock() and open files
		RSRESET
myl_Link	RS.L	1
myl_Key		RS.L	1
myl_Access	RS.L	1
myl_Task	RS.L	1
myl_Volume	RS.L	1
myl_Pos		RS.L	1	position in file (read/write)
myl_Data	RS.L	1	start of file data (read)
myl_Start	RS.L	1	start of block list (write)
myl_Block	RS.L	1	current block (write)
myl_BlockPos	RS.L	1	position in current block (write)
myl_Size	RS.L	1	size of file
myl_Mode	RS.B	1	0=simple lock, -1=write, 1=read
myl_Pad		RS.B	1
myl_SIZEOF	RS.W	0

* structure for file or dir
		RSRESET
myf_Link	RS.L	1	next file/dir
myf_Parent	RS.L	1	parent dir
myf_First	RS.L	0	dir:  points to first entry
myf_Size	RS.L	1	file: size of filedata
myf_Type	RS.B	1	-3=file, 0=hidden, 1=root, 2=dir
myf_Locks	RS.B	1	number of locks, -1=write lock
myf_DataOffs	RS.B	1	offset to start of data
myf_Name	RS.W	0	name (dynamic), then data

* private main structure
		RSRESET
CharTable	RS.B	256
DosBase		RS.L	1
MyProcess	RS.L	1
MyMsgPort	RS.L	1
MyMemPool	RS.L	1
MyDeviceNode	RS.L	1
MyVolumeBPTR	RS.L	1
NotifyList	RS.L	1
Copyfrom	RS.L	1
CopyfromLock	RS.L	1
CopyfromPort	RS.L	1
RootLock	RS.L	1
StartDate	RS.B	ds_SIZEOF
MyPacket	RS.B	sp_SIZEOF
VolumeNode	RS.B	DevList_SIZEOF
VolumeName	RS.B	MAXNAME
NotifyPort	RS.B	MP_SIZE
PacketPort	RS.B	MP_SIZE
FileSize	RS.L	1
TotalSize	RS.L	1
NumLocks	RS.L	1
Kickver		RS.W	1
WriteProtected	RS.B	1
NSignal		RS.B	1
PSignal		RS.B	1
Paddy1		RS.B	1
RootDir		RS.B	myf_Name+8
Paddy2		RS.B	3
TempPath	RS.B	MAXPATH
TempName	RS.B	MAXNAME
My_SIZEOF	RS.W	0

MyPkt		= MyPacket+sp_Pkt

*******************************************************

*******************************************************

;a4=DOSpacket
;a5=private struct
;a6=execbase
start:	movem.l	d2-d7/a2-a6,-(sp)	do some basic inits
	move.l	4.w,a6
	move.l	#My_SIZEOF,d0
	move.l	#MEMF_CLEAR!1,d1
	CALL	AllocMem
	tst.l	d0
	beq	exit1
	move.l	d0,a5
	DBUG1	txstart,a5
	lea	dosname(pc),a1
	moveq	#33,d0
	CALL	OpenLibrary
	move.l	d0,DosBase(a5)
	beq	exit2
	move.l	d0,a2
	CALL	Forbid
	move.l	dl_Root(a2),a0
	lea	rn_Time(a0),a0
	lea	StartDate(a5),a1
	move.l	(a0)+,(a1)+
	move.l	(a0)+,(a1)+
	move.l	(a0),(a1)
	CALL	Permit
	move.w	lib_Version(a6),Kickver(a5)
	sub.l	a1,a1
	CALL	FindTask
	move.l	d0,MyProcess(a5)
	cmp.w	#36,Kickver(a5)
	blo.s	.OS13
	move.l	d0,a0
	bset	#0,pr_Flags+3(a0)
.OS13	add.l	#pr_MsgPort,d0
	move.l	d0,MyMsgPort(a5)
	move.b	#1,RootDir+myf_Type(a5)
	cmp.w	#39,Kickver(a5)
	blo.s	.OS20
	moveq	#1,d0
	move.l	#5000,d1
	move.l	#2000,d2
	CALL	CreatePool
	move.l	d0,MyMemPool(a5)

.OS20	move.l	MyMsgPort(a5),a2	process startup message
	bsr	GetPacket
	move.l	d0,a4
	move.l	dp_Arg3(a4),d0
	lsl.l	#2,d0
	move.l	d0,MyDeviceNode(a5)
	move.l	d0,a0
	move.l	MyMsgPort(a5),dn_Task(a0)
	clr.l	dn_SegList(a0)
	move.l	dn_Name(a0),a0
	lea	RootDir+myf_Name(a5),a1
	moveq	#6,d0
	bsr	CopyBSTR2Char
	moveq	#DOS_TRUE,d0
	move.l	d0,dp_Res1(a4)
	bsr	ReplyPacket

	lea	VolumeNode(a5),a2	set up volume node
	move.l	a2,d0
	lsr.l	#2,d0
	move.l	d0,MyVolumeBPTR(a5)
	moveq	#2,d0
	move.l	d0,dl_Type(a2)
	move.l	MyMsgPort(a5),dl_Task(a2)
	move.l	#"DOS"<<8,dl_DiskType(a2)
	lea	volname(pc),a0
	lea	VolumeName(a5),a1
	moveq	#MAXNAME-2,d0
	bsr	CopyChar2BSTR
	move.l	d0,dl_Name(a2)
	IFD	VOLUME
	move.l	DosBase(a5),a0
	move.l	dl_Root(a0),a0
	move.l	rn_Info(a0),a0
	add.l	a0,a0
	add.l	a0,a0
	move.l	di_DevInfo(a0),d0
	move.l	d0,VolumeNode(a5)
	move.l	MyVolumeBPTR(a5),di_DevInfo(a0)
	ENDC

	bsr	InitConversion		init upper case table
	lea	NotifyPort(a5),a2	create msgport for notify
	move.b	#NT_MSGPORT,LN_TYPE(a2)
	moveq	#-1,d0
	CALL	AllocSignal
	tst.l	d0
	bmi	exit3
	move.b	d0,NSignal(a5)
	move.b	d0,MP_SIGBIT(a2)
	move.l	MyProcess(a5),MP_SIGTASK(a2)
	lea	MP_MSGLIST(a2),a0
	move.b	#NT_MESSAGE,LH_TYPE(a0)
	NEWLIST	a0
	lea	PacketPort(a5),a2	create msgport for DOSpackets
	move.b	#NT_MSGPORT,LN_TYPE(a2)
	moveq	#-1,d0
	CALL	AllocSignal
	tst.l	d0
	bmi	exit3
	move.b	d0,PSignal(a5)
	move.b	d0,MP_SIGBIT(a2)
	move.l	MyProcess(a5),MP_SIGTASK(a2)
	lea	MP_MSGLIST(a2),a0
	move.b	#NT_MESSAGE,LH_TYPE(a0)
	NEWLIST	a0
	lea	RootDir(a5),a2		create Lock for DiskInfo
	moveq	#ACCESS_READ,d2
	bsr	CreateLock
	move.l	d0,RootLock(a5)
	beq	exit4

	IFD	AUTOCOPY
	CALL	Forbid
	move.l	DosBase(a5),a0
	move.l	dl_Root(a0),a0
	move.l	rn_Info(a0),a0
	add.l	a0,a0
	add.l	a0,a0
	lea	di_DevInfo(a0),a2
.C	move.l	(a2),d0
	beq.s	.D
	lsl.l	#2,d0
	move.l	d0,a2
	move.l	dol_Name(a2),a0
	add.l	a0,a0
	add.l	a0,a0
	lea	sysdisk(pc),a1
	moveq	#0,d0
	move.b	(a0)+,d0
	bra.s	.F
.G	move.b	(a1)+,d1
	cmp.b	(a0)+,d1
	bne.s	.C
.F	dbra	d0,.G
	tst.b	(a1)
	bne.s	.C
	CALL	Permit
	move.l	a2,Copyfrom(a5)
	DBUG1	txcopy,Copyfrom(a5)
	bra.s	.A
.D	CALL	Permit
.A	ENDC

loop	move.l	MyMsgPort(a5),a2	enter main loop
	bsr	GetPacket
	move.l	d0,a4
	bsr	GetNotify
	clr.l	dp_Res1(a4)
	clr.l	dp_Res2(a4)
	move.l	dp_Type(a4),d0
	IFD	DEBUG
	move.l	dp_Port(a4),a1
	move.l	MP_SIGTASK(a1),a1
	move.l	LN_NAME(a1),a1
	DBUG5	txpack,d0,dp_Arg1(a4),dp_Arg2(a4),dp_Arg3(a4),a1
	ENDC
	move.l	d0,d1
	swap	d1
	tst.w	d1
	bne.s	.A
	lea	start(pc),a1
	lea	JumpTable(pc),a2
	moveq	#0,d2
.C	move.w	(a2)+,d1
	bpl.s	.E
.A	DBUG1	txerr1,d0
	move.w	#ERROR_ACTION_NOT_KNOWN,dp_Res2+2(a4)
	bra.s	.D
.E	move.w	(a2)+,d2
	cmp.w	d0,d1
	bne.s	.C
	add.l	d2,a1
	jsr	(a1)
.D	IFD	DEBUG
	moveq	#DOS_TRUE,d0
	cmp.l	dp_Res1(a4),d0
	beq.s	.H
	DBUG2	txres,dp_Res1(a4),dp_Res2(a4)
.H	ENDC
	bsr	ReplyPacket
	bra	loop

AExit	addq.l	#4,sp		exit routine
	moveq	#DOS_TRUE,d0
	move.l	d0,dp_Res1(a4)
	bsr	ReplyPacket
	IFND	DEBUG
	move.l	NumLocks(a5),d0
	subq.l	#1,d0
	bne	loop
	ENDC
	move.l	RootLock(a5),a1
	bsr	FreeLock
exit4	move.l	MyDeviceNode(a5),a0
	clr.l	dn_Task(a0)
	bsr	FlushPackets
	IFD	VOLUME
	move.l	DosBase(a5),a0
	move.l	dl_Root(a0),a0
	move.l	rn_Info(a0),a0
	add.l	a0,a0
	add.l	a0,a0
	move.l	VolumeNode(a5),d0
	move.l	d0,di_DevInfo(a0)
	ENDC

	moveq	#0,d0
	move.b	PSignal(a5),d0
	CALL	FreeSignal
	moveq	#0,d0
	move.b	NSignal(a5),d0
	CALL	FreeSignal
exit3	move.l	DosBase(a5),a1
	CALL	CloseLibrary
exit2	move.l	MyDeviceNode(a5),a0
	clr.l	dn_Task(a0)
	DBUG2	txend,FileSize(a5),TotalSize(a5)
	move.l	MyMemPool(a5),d0
	beq.s	.A
	move.l	d0,a0
	CALL	DeletePool
.A	move.l	a5,a1
	move.l	#My_SIZEOF,d0
	CALL	FreeMem
exit1	movem.l	(sp)+,d2-d7/a2-a6
	moveq	#0,d0
	rts

*******************************************************

JumpTable:
	dc.w	ACTION_NIL,NoAction-start
;	dc.w	ACTION_SET_PROTECT,NoAction-start
;	dc.w	ACTION_SET_COMMENT,NoAction-start
;	dc.w	ACTION_SET_DATE,NoAction-start
	dc.w	ACTION_FLUSH,NoAction-start
	dc.w	ACTION_IS_FILESYSTEM,NoAction-start

	dc.w	ACTION_DIE,AExit-start
	dc.w	ACTION_CURRENT_VOLUME,ACurrentVolume-start
	dc.w	ACTION_RENAME_DISK,ARenameDisk-start
	dc.w	ACTION_WRITE_PROTECT,AWriteProtect-start

	dc.w	ACTION_FINDUPDATE,AOpenNewfile-start
	dc.w	ACTION_FINDINPUT,AOpenOldfile-start
	dc.w	ACTION_FINDOUTPUT,AOpenNewfile-start
	dc.w	ACTION_END,ACloseFile-start
	dc.w	ACTION_SEEK,ASeekPosition-start
	dc.w	ACTION_READ,AReadFile-start
	dc.w	ACTION_WRITE,AWriteFile-start
	dc.w	ACTION_DELETE_OBJECT,ADeleteObject-start
	dc.w	ACTION_RENAME_OBJECT,ARenameObject-start
	dc.w	ACTION_CREATE_DIR,ACreateDir-start

	dc.w	ACTION_LOCATE_OBJECT,ALocateObject-start
	dc.w	ACTION_PARENT,AParentDir-start
	dc.w	ACTION_COPY_DIR,ADuplicateLock-start
	dc.w	ACTION_FREE_LOCK,AFreeLock-start
	dc.w	ACTION_SAME_LOCK,ASameLock-start
	dc.w	ACTION_EXAMINE_OBJECT,AExamineObject-start
	dc.w	ACTION_EXAMINE_FH,AExamineFH-start
	dc.w	ACTION_EXAMINE_NEXT,AExamineNext-start
	dc.w	ACTION_DISK_INFO,ADiskInfo1-start
	dc.w	ACTION_INFO,ADiskInfo2-start

	dc.w	ACTION_ADD_NOTIFY,AAddNotify-start
	dc.w	ACTION_REMOVE_NOTIFY,ARemoveNotify-start
	dc.w	ACTION_SET_FILE_SIZE,ASetFileSize-start
	dc.w	ACTION_FH_FROM_LOCK,AFHfromLock-start
;	dc.w	ACTION_CHANGE_MODE,AChangeMode-start
	dc.w	ACTION_COPY_DIR_FH,ADupLockFromFH-start
	dc.w	ACTION_PARENT_FH,AParentFromFH-start
	dc.w	-1

		IFD	VOLUME
volname		dc.b	"Environment",0
		ENDC
		IFND	VOLUME
volname		dc.b	"Env",0
		ENDC
version		dc.b	"$VER: HappyENV-Handler 0.8 (31.8.96)",10,0
dosname		dc.b	"dos.library",0
utilname	dc.b	"utility.library",0
sysdisk		dc.b	"ENVARC",0
		even

*******************************************************

* Init to-upper-conversion table
InitConversion:
	lea	CharTable(a5),a2
	move.w	#255,d0
.A	move.b	d0,0(a2,d0.w)
	dbra	d0,.A
	moveq	#"A",d0
.C	move.b	d0,"a"-"A"(a2,d0.w)
	addq.w	#1,d0
	cmp.b	#"Z"+1,d0
	bne.s	.C
	move.w	#192,d0
.F	move.b	d0,224-192(a2,d0.w)
	addq.w	#1,d0
	cmp.b	#222+1,d0
	bne.s	.F

	lea	utilname(pc),a1	open utility.library
	moveq	#37,d0
	CALL	OpenLibrary
	tst.l	d0
	beq.s	.D
	move.l	d0,a6
	move.w	#255,d2
.E	move.w	d2,d0
	CALL	ToUpper
	move.b	d0,0(a2,d2.w)
	dbra	d2,.E
	move.l	a6,a1
	move.l	4.w,a6
	CALL	CloseLibrary
.D	rts


* Wait for a packet, then get it
* ENTRY: a2=msgport
* EXIT:  d0=packet
GetPacket:
.A	move.l	a2,a0
	CALL	WaitPort
	move.l	a2,a0
	CALL	GetMsg
	tst.l	d0
	beq.s	.A
	move.l	d0,a0
	move.l	mn_Node+LN_NAME(a0),d0
	beq.s	.A
	rts

* Reply packet in a4
ReplyPacket:
	move.l	a4,a2
	move.l	dp_Port(a4),a0		reply port
	move.l	MyMsgPort(a5),dp_Port(a2)
* ENTRY: a2=packet to send, a0=msgport to send to
SendPacket:
	move.l	dp_Link(a2),a1		message to send
	move.l	a2,mn_Node+LN_NAME(a1)
	clr.l	mn_Node+LN_SUCC(a1)
	clr.l	mn_Node+LN_PRED(a1)
	move.b	#NT_MESSAGE,mn_Node+LN_TYPE(a1)
	CALL	PutMsg
	rts

FlushPackets:
.A	move.l	MyMsgPort(a5),a0
	CALL	GetMsg
	tst.l	d0
	beq.s	.C
	move.l	d0,a0
	move.l	mn_Node+LN_NAME(a0),d0
	beq.s	.A
	move.l	d0,a4
	clr.l	dp_Res1(a4)
	move.w	#ERROR_ACTION_NOT_KNOWN,dp_Res2+2(a4)
	bsr	ReplyPacket
	bra.s	.A
.C	rts

* Send a packet to the handler in CopyfromPort and wait for a reply
* ENTRY: d0=dp_Type, d1=dp_Arg1, d2=dp_Arg2, d3=dp_Arg3
* EXIT:  d0=dp_Res1, d1=dp_Res2, Z-flag
DoPacket:
	move.l	a2,-(sp)
	lea	MyPacket(a5),a1
	lea	sp_Pkt(a1),a2
	move.l	a1,dp_Link(a2)
	lea	PacketPort(a5),a1
	move.l	a1,dp_Port(a2)
	move.l	d0,dp_Type(a2)
	move.l	d1,dp_Arg1(a2)
	move.l	d2,dp_Arg2(a2)
	move.l	d3,dp_Arg3(a2)
	move.l	CopyfromPort(a5),a0
	bsr	SendPacket
	lea	PacketPort(a5),a2
	bsr	GetPacket
	move.l	d0,a0
	DBUG4	txpkt,a0,dp_Type(a0),dp_Res1(a0),dp_Res2(a0)
;	bsr	wait_c
	move.l	dp_Res2(a0),d1
	move.l	dp_Res1(a0),d0
	move.l	(sp)+,a2
	rts

*******************************************************

*******************************************************

NoAction:
	moveq	#DOS_TRUE,d0
	move.l	d0,dp_Res1(a4)
	rts

ACurrentVolume:
	move.l	MyVolumeBPTR(a5),dp_Res1(a4)
	rts

ARenameDisk:
	move.w	#ERROR_DISK_WRITE_PROTECTED,dp_Res2+2(a4)
	tst.b	WriteProtected(a5)
	bne.s	.fail
	move.l	dp_Arg1(a4),a0
	lea	TempName(a5),a1
	moveq	#MAXNAME-2,d0
	bsr	CopyBSTR2Char
	lea	TempName(a5),a0
	lea	VolumeName(a5),a1
	moveq	#MAXNAME-2,d0
	bsr	CopyChar2BSTR
	moveq	#DOS_TRUE,d0
	move.l	d0,dp_Res1(a4)
.fail	rts

AWriteProtect:
	move.l	dp_Arg1(a4),d0
	move.b	d0,WriteProtected(a5)
	moveq	#DOS_TRUE,d0
	move.l	d0,dp_Res1(a4)
	rts	

AOpenOldfile:
	move.l	dp_Arg3(a4),a0
	move.l	dp_Arg2(a4),d0
	moveq	#ACCESS_READ,d2
	bsr	LocateObject
OpnOld:	move.l	dp_Arg1(a4),a3
	add.l	a3,a3
	add.l	a3,a3
	clr.l	fh_Interactive(a3)
	move.l	d0,fh_Arg1(a3)
	beq.s	.fail
	move.l	d0,a0
	move.l	myl_Key(a0),a1
	move.w	#ERROR_OBJECT_WRONG_TYPE,dp_Res2+2(a4)
	tst.b	myf_Type(a1)	do not open dirs
	bmi.s	.A
	move.l	a0,a1
	bsr	FreeLock
	bra.s	.fail
.A	clr.l	myl_Pos(a0)
	move.l	myf_Size(a1),myl_Size(a0)
	moveq	#0,d0
	move.b	myf_DataOffs(a1),d0
	add.l	d0,a1
	move.l	a1,myl_Data(a0)
	clr.l	myl_Start(a0)
	clr.l	myl_Block(a0)
	clr.l	myl_BlockPos(a0)
	move.b	#1,myl_Mode(a0)
	moveq	#DOS_TRUE,d0
	move.l	d0,dp_Res1(a4)
	DBUG1	txopeno,fh_Arg1(a3)
.fail	rts

AOpenNewfile:
	move.w	#ERROR_DISK_WRITE_PROTECTED,dp_Res2+2(a4)
	tst.b	WriteProtected(a5)
	bne	.fail
	move.w	#ERROR_OBJECT_EXISTS,dp_Res2+2(a4)
	move.l	dp_Arg1(a4),a3
	add.l	a3,a3
	add.l	a3,a3
	clr.l	fh_Interactive(a3)
	move.l	dp_Arg2(a4),d0	does file already exist ?
	move.l	dp_Arg3(a4),a0
	bsr	DelSearchObject
	beq.s	.A
	move.l	d0,a1
	tst.b	myf_Type(a1)	do not overwrite dirs
	bpl	.fail
	bsr	DeleteObject
	beq	.fail
.A	bsr	SplitPath
	move.w	#ERROR_DIR_NOT_FOUND,dp_Res2+2(a4)
	move.l	dp_Arg2(a4),d0
	bsr	CreatePath
	beq	.fail
	move.l	a3,-(sp)
	move.l	d0,a3
	lea	TempName(a5),a2
	moveq	#0,d2
	bsr	CreateNewObject
	move.l	(sp)+,a3
	beq.s	.fail
	move.l	d0,a2
	moveq	#ACCESS_WRITE,d2
	bsr	CreateLock
	move.l	d0,fh_Arg1(a3)
	beq.s	.fail
	move.l	d0,a0
	move.b	#-1,myl_Mode(a0)
	clr.l	myl_Pos(a0)
	clr.l	myl_Data(a0)
	clr.l	myl_Start(a0)
	clr.l	myl_Block(a0)
	clr.l	myl_BlockPos(a0)
	clr.l	myl_Size(a0)
	moveq	#DOS_TRUE,d0
	move.l	d0,dp_Res1(a4)
	DBUG1	txopenn,fh_Arg1(a3)
.fail	rts

ACloseFile:
	move.l	dp_Arg1(a4),a1
	cmp.b	#-1,myl_Mode(a1)
	beq.s	.D
	bsr	FreeLock
	bra.s	.ok
.D	move.l	myl_Size(a1),d2
	move.l	myl_Key(a1),a2
	move.l	myf_Parent(a2),a3
	lea	myf_Name(a2),a2
	bsr	CreateNewObject
	beq.s	.fail
	move.l	d0,d4
	move.l	d0,a3
	add.l	d1,a3
	move.l	dp_Arg1(a4),a2
	move.l	myl_Start(a2),d3
.F	tst.l	d3
	beq.s	.A
	move.l	d3,-(sp)
	move.l	d3,a0
	move.l	(a0)+,d3
	move.l	(a0)+,d2
	move.l	a3,a1
	move.l	d2,d0
	CALL	CopyMem
	add.l	d2,a3
	move.l	d2,d0
	addq.l	#8,d0
	move.l	(sp)+,a1
	bsr	FreeMem
	bra.s	.F
.A	move.l	a2,a1
	move.l	myl_Key(a2),a2
	bsr	FreeLock
	move.l	a2,a1
	bsr	DeleteObj
	beq.s	.fail
	move.l	d4,a0
	bsr	CheckNotify
.ok	moveq	#DOS_TRUE,d0
	move.l	d0,dp_Res1(a4)
.fail	rts

AWriteFile:
	move.w	#ERROR_DISK_WRITE_PROTECTED,dp_Res2+2(a4)
	tst.b	WriteProtected(a5)
	bne	.fail
	moveq	#-1,d0
	move.l	d0,dp_Res1(a4)
	move.l	dp_Arg1(a4),a2	lock
	move.l	dp_Arg2(a4),a3	buffer
	move.l	dp_Arg3(a4),d3	length
	move.w	#ERROR_WRITE_PROTECTED,dp_Res2+2(a4)
	cmp.b	#-1,myl_Mode(a2)
	bne	.fail
.F	move.l	d3,d2
	move.l	myl_Block(a2),d0
	beq	.E
	move.l	d0,a1
	move.l	4(a1),d0
	sub.l	myl_BlockPos(a2),d0
	beq.s	.C
	bmi.s	.C
	cmp.l	d2,d0
	bhs.s	.D
	move.l	d0,d2
.D	addq.l	#8,a1
	add.l	myl_BlockPos(a2),a1
	move.l	a3,a0
	move.l	d2,d0
	CALL	CopyMem
	DBUG2	txwins,d2,myl_Pos(a2)
	add.l	d2,a3
	add.l	d2,myl_Pos(a2)
	add.l	d2,myl_BlockPos(a2)
	sub.l	d2,d3
	beq.s	.ok
	bra.s	.F
.C	move.l	(a1),d0
	beq.s	.E
	move.l	d0,myl_Block(a2)
	clr.l	myl_BlockPos(a2)
	bra	.F	
	
.E	move.w	#ERROR_DISK_FULL,dp_Res2+2(a4)
	move.l	d3,d0
	addq.l	#8,d0
	bsr	AllocMem
	beq	.fail
	move.l	myl_Block(a2),a0
	move.l	d0,myl_Block(a2)
	move.l	a0,d1
	bne.s	.A
	lea	myl_Start(a2),a0
.A	move.l	d0,(a0)

	move.l	d3,d2
	move.l	d0,a1
	clr.l	(a1)+
	move.l	d2,(a1)+
	move.l	a3,a0
	move.l	d2,d0
	CALL	CopyMem
	add.l	d2,myl_Size(a2)
	add.l	d2,myl_Pos(a2)
	move.l	d2,myl_BlockPos(a2)
.ok	move.l	dp_Arg3(a4),dp_Res1(a4)
	clr.w	dp_Res2+2(a4)
	DBUG3	txwrite,dp_Arg3(a4),myl_Pos(a2),myl_Size(a2)
.fail	rts

AReadFile:
	moveq	#-1,d0
	move.l	d0,dp_Res1(a4)
	move.l	dp_Arg1(a4),a2
	move.w	#ERROR_READ_PROTECTED,dp_Res2+2(a4)
	cmp.b	#1,myl_Mode(a2)
	bne.s	.fail
	move.l	myl_Size(a2),d0
	move.l	myl_Pos(a2),a0
	sub.l	a0,d0
	move.l	dp_Arg3(a4),d2
	cmp.l	d0,d2
	bls.s	.A
	exg.l	d0,d2
.A	move.l	myl_Data(a2),d0
	add.l	d0,a0
	move.l	dp_Arg2(a4),a1
	move.l	d2,d0
	CALL	CopyMem
	add.l	d2,myl_Pos(a2)
	move.l	d2,dp_Res1(a4)
	clr.w	dp_Res2+2(a4)
	DBUG3	txread,d2,dp_Arg3(a4),myl_Pos(a2)
.fail	rts

ASeekPosition
	move.l	dp_Arg1(a4),a2
	move.l	dp_Arg2(a4),d1	position
	move.l	dp_Arg3(a4),d2	mode
	clr.w	dp_Res2+2(a4)
	move.l	myl_Pos(a2),d3
	move.l	myl_Size(a2),d4

	moveq	#OFFSET_BEGINNING,d0
	cmp.l	d0,d2
	beq.s	.E
	moveq	#OFFSET_END,d0
	cmp.l	d0,d2
	bne.s	.C
	add.l	d4,d1
	bra.s	.E
.C	moveq	#OFFSET_CURRENT,d0
	cmp.l	d0,d2
	bne.s	.fail
	add.l	d3,d1
.E	move.l	d1,myl_Pos(a2)
	bmi.s	.A
	cmp.l	d1,d4
	bhs.s	Seeek
	move.l	d4,myl_Pos(a2)
	bra.s	.fail
.A	clr.l	myl_Pos(a2)
.fail	move.w	#ERROR_SEEK_ERROR,dp_Res2+2(a4)
	moveq	#-1,d3

Seeek	cmp.b	#-1,myl_Mode(a2)
	bne.s	.A
	move.l	myl_Pos(a2),d2
	move.l	myl_Start(a2),d0
	beq.s	.A
	bra.s	.E
.D	move.l	(a0),d0
	beq.s	.C
.E	move.l	d0,a0
	move.l	4(a0),d1
	sub.l	d1,d2
	beq.s	.F
	bpl.s	.D
.F	add.l	d1,d2
.C	move.l	a0,myl_Block(a2)
	move.l	d2,myl_BlockPos(a2)
.A	move.l	d3,dp_Res1(a4)
	DBUG1	txseek,myl_Pos(a2)
	rts

ADeleteObject:
	move.w	#ERROR_DISK_WRITE_PROTECTED,dp_Res2+2(a4)
	tst.b	WriteProtected(a5)
	bne.s	.fail
	move.w	#ERROR_OBJECT_NOT_FOUND,dp_Res2+2(a4)
	move.l	dp_Arg1(a4),d0
	move.l	dp_Arg2(a4),a0
	bsr	SearchObject
	beq.s	.fail
	movem.l	d0-d1,-(sp)
	move.l	d0,a0
	moveq	#1,d0
	bsr	NotifyObject
	movem.l	(sp)+,d0-d1
	move.l	d0,a1
	bsr	DeleteObject
	beq.s	.fail
	moveq	#DOS_TRUE,d0
	move.l	d0,dp_Res1(a4)
.fail	rts

ARenameObject:
	move.w	#ERROR_DISK_WRITE_PROTECTED,dp_Res2+2(a4)
	tst.b	WriteProtected(a5)
	bne	.fail
	move.w	#ERROR_OBJECT_NOT_FOUND,dp_Res2+2(a4)
	move.l	dp_Arg1(a4),d0
	move.l	dp_Arg2(a4),a0
	bsr	SearchObject
	beq	.fail
	move.l	d0,a3
	move.l	d1,d3
	move.w	#ERROR_OBJECT_IN_USE,dp_Res2+2(a4)
	tst.b	myf_Locks(a3)
	bne	.fail
	move.l	a3,a0
	bsr	NotifyObject
	move.w	#ERROR_OBJECT_EXISTS,dp_Res2+2(a4)
	move.l	dp_Arg3(a4),d0
	move.l	dp_Arg4(a4),a0
	bsr	DelSearchObject
	bne	.fail
	bsr	SplitPath
	move.w	#ERROR_DIR_NOT_FOUND,dp_Res2+2(a4)
	move.l	dp_Arg3(a4),d0
	bsr	SearchPath
	beq	.fail
	move.l	a3,-(sp)
	moveq	#0,d2
	tst.b	myf_Type(a3)
	bpl.s	.D
	move.l	myf_Size(a3),d2
.D	move.l	d0,a3
	lea	TempName(a5),a2
	bsr	CreateNewObject
	move.l	(sp)+,a3
	beq.s	.fail
	move.l	d0,a2
	move.b	myf_Type(a3),myf_Type(a2)
	bpl.s	.A
	move.l	a2,a1		rename file
	add.l	d1,a1
	move.l	a3,a0
	moveq	#0,d0
	move.b	myf_DataOffs(a3),d0
	add.l	d0,a0
	move.l	myf_Size(a3),d0
	CALL	CopyMem
	bra.s	.C
.A	move.l	myf_First(a3),d0	rename dir
	clr.l	myf_First(a3)
	move.l	d0,myf_First(a2)
	beq.s	.C
.E	move.l	d0,a0
	move.l	a2,myf_Parent(a0)
	move.l	myf_Link(a0),d0
	bne.s	.E
.C	move.l	d3,d1		end rename
	move.l	a3,a1
	bsr	DeleteObject
	beq.s	.fail
	move.l	a2,a0
	bsr	CheckNotify
	moveq	#DOS_TRUE,d0
	move.l	d0,dp_Res1(a4)
.fail	rts

*******************************************************

ALocateObject:
	move.l	dp_Arg1(a4),d0
	move.l	dp_Arg2(a4),a0
	move.l	dp_Arg3(a4),d2
	bsr	LocateObject
	lsr.l	#2,d0
	move.l	d0,dp_Res1(a4)
	rts

ADupLockFromFH:
	move.l	dp_Arg1(a4),d0
	bra.s	DupLock

ADuplicateLock:
	move.l	dp_Arg1(a4),d0
	lsl.l	#2,d0
DupLock	beq.s	.fail
	move.l	d0,a0
	move.l	myl_Key(a0),a2
	moveq	#ACCESS_READ,d2
	bsr	CreateLock
	lsr.l	#2,d0
	move.l	d0,dp_Res1(a4)
.fail	rts

AParentFromFH:
	move.l	dp_Arg1(a4),d0
	bra.s	ParentD
AParentDir:
	move.l	dp_Arg1(a4),d0
	lsl.l	#2,d0
ParentD	beq.s	.fail
	move.l	d0,a0
	move.l	myl_Key(a0),a2
	move.l	myf_Parent(a2),d0
	beq.s	.fail
	move.l	d0,a2
	moveq	#ACCESS_READ,d2
	bsr	CreateLock
	lsr.l	#2,d0
	move.l	d0,dp_Res1(a4)
.fail	rts

AFreeLock:
	move.l	dp_Arg1(a4),d0
	beq.s	.fail
	lsl.l	#2,d0
	move.l	d0,a1
	bsr	FreeLock
	moveq	#DOS_TRUE,d0
	move.l	d0,dp_Res1(a4)
.fail	rts

ASameLock:
	moveq	#LOCK_SAME_VOLUME,d0
	move.l	d0,dp_Res1(a4)
	move.l	dp_Arg1(a4),a0
	add.l	a0,a0
	add.l	a0,a0
	move.l	dp_Arg2(a4),a1
	add.l	a1,a1
	add.l	a1,a1
	move.l	myl_Key(a0),d0
	cmp.l	myl_Key(a1),d0
	bne.s	.A
	moveq	#LOCK_SAME,d0
	move.l	d0,dp_Res1(a4)
.A	rts

AExamineFH:
	move.l	dp_Arg1(a4),a0
	bra.s	Exami

AExamineObject:
	move.l	dp_Arg1(a4),a0
	add.l	a0,a0
	add.l	a0,a0
Exami	move.l	myl_Key(a0),a0
	move.l	dp_Arg2(a4),a1
	add.l	a1,a1
	add.l	a1,a1
	DBUG1	txexam,a0
	move.l	a1,a2
	moveq	#fib_SIZEOF/4-1,d0
.D	clr.l	(a2)+
	dbra	d0,.D
* ENTRY: a0=file, a1=fib
ExamineObject:
	moveq	#0,d1
	move.b	myf_Type(a0),d0
	ext.w	d0
	ext.l	d0
	IFD	DEBUG
	bne.s	.C
	moveq	#-5,d0
.C	ENDC
	move.l	d0,fib_DirEntryType(a1)
	move.l	d0,fib_EntryType(a1)
	bpl.s	.A
	move.l	myf_Size(a0),d1
.A	move.l	a0,fib_DiskKey(a1)
	move.l	d1,fib_Size(a1)
	add.l	#1023,d1
	lsr.l	#8,d1
	lsr.l	#2,d1
	move.l	d1,fib_NumBlocks(a1)
	move.l	StartDate+0(a5),fib_DateStamp+0(a1)
	move.l	StartDate+4(a5),fib_DateStamp+4(a1)
	move.l	StartDate+8(a5),fib_DateStamp+8(a1)
	lea	myf_Name(a0),a0
	lea	fib_FileName(a1),a1
	moveq	#106,d0
	bsr	CopyChar2BSTR
	moveq	#DOS_TRUE,d0
	move.l	d0,dp_Res1(a4)
	rts

AExamineNext:
	move.l	dp_Arg1(a4),a2
	add.l	a2,a2
	add.l	a2,a2
	move.l	dp_Arg2(a4),a1
	add.l	a1,a1
	add.l	a1,a1
	move.l	fib_DiskKey(a1),a0
	DBUG1	txexnx,a0
	cmp.l	myl_Key(a2),a0
	bne.s	.A
	move.w	#ERROR_OBJECT_WRONG_TYPE,dp_Res2+2(a4)
	tst.b	myf_Type(a0)
	bmi.s	.fail
	move.l	myf_First-myf_Link(a0),a0
	bra.s	.C
.A	move.l	myf_Link(a0),a0
.C	move.w	#ERROR_NO_MORE_ENTRIES,dp_Res2+2(a4)
	move.l	a0,d0
	beq.s	.fail
	IFND	DEBUG
	tst.b	myf_Type(a0)
	beq.s	.A
	ENDC
	bra	ExamineObject
.fail	rts

ADiskInfo1:
	move.l	dp_Arg1(a4),a0
	bra.s	DiskInfo
ADiskInfo2:
	move.l	dp_Arg2(a4),a0
DiskInfo:
	add.l	a0,a0
	add.l	a0,a0
	move.l	a0,a1
	moveq	#id_SIZEOF/4-1,d0
.D	clr.l	(a1)+
	dbra	d0,.D
	IFD	DEBUG
	move.l	NumLocks(a5),id_NumSoftErrors(a0)
	ENDC
	moveq	#ID_VALIDATED,d0
	tst.b	WriteProtected(a5)
	beq.s	.C
	moveq	#ID_WRITE_PROTECTED,d0
.C	move.l	d0,id_DiskState(a0)
	move.l	#1024,d1
	move.l	d1,id_BytesPerBlock(a0)
	lsr.l	#1,d1
	move.l	FileSize(a5),d0
	add.l	d1,d0
	lsr.l	#8,d0
	lsr.l	#2,d0
	move.l	d0,id_NumBlocksUsed(a0)
	move.l	TotalSize(a5),d0
	add.l	d1,d0
	lsr.l	#8,d0
	lsr.l	#2,d0
	bne.s	.A
	moveq	#1,d0
.A	move.l	d0,id_NumBlocks(a0)
	move.l	#"DOS"<<8,id_DiskType(a0)
	move.l	MyVolumeBPTR(a5),id_VolumeNode(a0)
	move.l	RootLock(a5),id_InUse(a0)
	moveq	#DOS_TRUE,d0
	move.l	d0,dp_Res1(a4)
	rts

ACreateDir:
	move.w	#ERROR_DISK_WRITE_PROTECTED,dp_Res2+2(a4)
	tst.b	WriteProtected(a5)
	bne.s	.fail
	move.w	#ERROR_OBJECT_EXISTS,dp_Res2+2(a4)
	move.l	dp_Arg1(a4),d0
	move.l	dp_Arg2(a4),a0
	bsr	DelSearchObject
	bne.s	.fail
	bsr	SplitPath
	move.w	#ERROR_DIR_NOT_FOUND,dp_Res2+2(a4)
	move.l	dp_Arg1(a4),d0
	bsr	CreatePath
	beq.s	.fail
	move.l	d0,a3
	lea	TempName(a5),a2
	moveq	#0,d2
	bsr	CreateNewObject
	beq.s	.fail
	move.l	d0,a2
	move.b	#2,myf_Type(a2)
	moveq	#ACCESS_WRITE,d2
	bsr	CreateLock
	beq.s	.fail
	move.l	d0,a0
	lsr.l	#2,d0
	move.l	d0,dp_Res1(a4)
	move.l	myl_Key(a0),a0
	bsr	CheckNotify
.fail	rts

*******************************************************

ASetFileSize:
	move.l	dp_Arg1(a4),a2
	move.l	myl_Size(a2),dp_Res1(a4)
	rts

AFHfromLock:
	move.w	#ERROR_WRITE_PROTECTED,dp_Res2+2(a4)
	move.l	dp_Arg2(a4),d0
	beq.s	.fail
	lsl.l	#2,d0
	move.l	d0,a0
	moveq	#ACCESS_READ,d1	read access supported only
	cmp.l	myl_Access(a0),d1
	bne.s	.fail
	move.l	myl_Key(a0),a0
	move.w	#ERROR_OBJECT_WRONG_TYPE,dp_Res2+2(a4)
	tst.b	myf_Type(a0)	do not open dirs
	bmi	OpnOld
.fail	rts

AChangeMode:
	rts

*******************************************************

AAddNotify:
	move.w	#ERROR_NO_FREE_STORE,dp_Res2+2(a4)
	move.l	dp_Arg1(a4),a3
	move.l	#myn_SIZEOF,d0
	bsr	AllocMem
	beq.s	.fail
	move.l	d0,a2
	lea	NotifyList(a5),a0
	move.l	(a0),myn_Link(a2)
	move.l	a2,(a0)
	move.l	a3,myn_Request(a2)
	move.l	nr_FullName(a3),a0
	lea	myn_Name(a2),a1
	moveq	#MAXPATH-1,d0
	bsr	CopyChar2Char
	lea	myn_Name(a2),a0
	lea	TempPath(a5),a1
	moveq	#MAXPATH-1,d0
	bsr	CopyChar2Char
	moveq	#0,d0
	bsr	SearchPath
	move.l	d0,myn_Key(a2)
	IFD	DEBUG
	lea	myn_Name(a2),a0
	DBUG4	txanoti,a2,a3,a0,d0
	ENDC
	move.l	nr_Flags(a3),d0
	btst	#NRB_NOTIFY_INITIAL,d0
	beq.s	.A
	bsr	SendNotify
.A	moveq	#DOS_TRUE,d0
	move.l	d0,dp_Res1(a4)
.fail	rts

ARemoveNotify:
	move.w	#ERROR_OBJECT_IN_USE,dp_Res2+2(a4)
	move.l	dp_Arg1(a4),a2
	tst.l	nr_MsgCount(a2)
	bne.s	.fail
	move.w	#ERROR_OBJECT_NOT_FOUND,dp_Res2+2(a4)
	lea	NotifyList(a5),a1
.A	move.l	(a1),d0
	beq.s	.fail
	move.l	a1,a0
	move.l	d0,a1
	cmp.l	myn_Request(a1),a2
	bne.s	.A
	move.l	myn_Link(a1),myn_Link(a0)
	DBUG2	txrnoti,a1,a2
	move.l	#myn_SIZEOF,d0
	bsr	FreeMem
	moveq	#DOS_TRUE,d0
	move.l	d0,dp_Res1(a4)
.fail	rts

* Update myn_Key of notification list and do notify
* ENTRY: a0=file
UpdateNotify:
	move.l	a2,-(sp)
	lea	NotifyList(a5),a2
	bra.s	.A
.C	move.l	d0,a2
	tst.l	myn_Key(a2)
	bne.s	.A
	lea	myn_Name(a2),a0
	lea	TempPath(a5),a1
	moveq	#MAXPATH-1,d0
	bsr	CopyChar2Char
	moveq	#0,d0
	bsr	SearchPath
	move.l	d0,myn_Key(a2)
	IFD	DEBUG
	beq.s	.A
	lea	myn_Name(a2),a0
	DBUG2	txunoti,a0,d0
	ENDC
.A	move.l	(a2),d0
	bne.s	.C
	move.l	(sp)+,a2
	rts

* Check notification list for file/dir and parent dir and notify it.
* ENTRY: a0=file
CheckNotify:
	move.l	a0,-(sp)
	IFD	DEBUG
	lea	myf_Name(a0),a0
	DBUG1	txcnoti,a0
	ENDC
	bsr	UpdateNotify
	move.l	(sp)+,a0
NotifyObject:
	bsr	NotifyObj
	move.l	myf_Parent(a0),d1
	move.l	d1,a0
	beq.s	.E
	bsr	NotifyObj
.E	rts

NotifyObj:
	movem.l	a2/a3,-(sp)
	lea	NotifyList(a5),a2
	bra.s	.A
.C	move.l	d0,a2
	cmp.l	myn_Key(a2),a0
	bne.s	.A
	move.l	a0,-(sp)
	move.l	myn_Request(a2),a3
	bsr	SendNotify
	move.l	(sp)+,a0
.A	move.l	(a2),d0
	bne.s	.C
	movem.l	(sp)+,a2/a3
	rts

* Send a Notify message or set a Notify signal
* ENTRY: a3=NotifyRequest
SendNotify:
	btst	#NRB_SEND_SIGNAL,nr_Flags+3(a3)
	beq.s	.C
	move.l	nr_Task(a3),a1
	IFD	DEBUG
	move.l	LN_NAME(a1),d0
	lea	myn_Name(a2),a0
	DBUG2	txsnoti,d0,a0
	ENDC
	moveq	#0,d0
	move.b	nr_SignalNum(a3),d1
	bset	d1,d0
	CALL	Signal
	rts

.C	btst	#NRB_SEND_MESSAGE,nr_Flags+3(a3)
	beq	.D
	moveq	#NotifyMessage_SIZEOF,d0
	bsr	AllocMem
	beq	.D
	move.l	d0,a0
	move.l	d0,a1
	moveq	#NotifyMessage_SIZEOF/2-1,d0
.A	clr.w	(a0)+
	dbra	d0,.A
	move.b	#NT_MESSAGE,LN_TYPE(a1)
	lea	NotifyPort(a5),a0
	move.l	a0,MN_REPLYPORT(a1)
	move.w	#NotifyMessage_SIZEOF,MN_LENGTH(a1)
	move.l	#$40000000,nm_Class(a1)
	move.w	#$1234,nm_Code(a1)
	move.l	a3,nm_NReq(a1)
	IFD	DEBUG
	move.l	a2,-(sp)
	move.l	nr_Port(a3),a0
	move.l	MP_SIGTASK(a0),a0
	move.l	LN_NAME(a0),a0
	lea	myn_Name(a2),a2
	DBUG3	txmnoti,a1,a0,a2
	move.l	(sp)+,a2
	ENDC
	move.l	nr_Port(a3),a0
	CALL	PutMsg
	addq.l	#1,nr_MsgCount(a3)
;	btst	#NRB_WAIT_REPLY,nr_Flags+3(a3)
;	beq.s	.D
;	lea	NotifyPort(a5),a0
;	CALL	WaitPort
;	bsr	GetNotify
.D	rts

* Handle replies of Notify message
GetNotify:
.A	lea	NotifyPort(a5),a0
	CALL	GetMsg
	tst.l	d0
	beq.s	.E
	move.l	d0,a1
	DBUG1	txgnoti,a1
	move.l	nm_NReq(a1),a0
	subq.l	#1,nr_MsgCount(a0)
	moveq	#NotifyMessage_SIZEOF,d0
	bsr	FreeMem
	bra.s	.A
.E	rts

*******************************************************

*******************************************************

* ENTRY: a2=name, a3=parent dir, d2=data size
* EXIT:  d1=offset of data, d0=new file, Z-flag
CreateNewObject:
	move.w	#ERROR_DISK_FULL,dp_Res2+2(a4)
CreateNewObj:
	movem.l	d3/a2-a3,-(sp)
	move.l	a2,a0
	moveq	#myf_Name,d3
.D	addq.l	#1,d3
	tst.b	(a0)+
	bne.s	.D
	addq.l	#1,d3
	bclr	#0,d3
	move.l	d3,d0
	add.l	d2,d0
	bsr	AllocMem
	beq.s	.fail
	move.l	d0,a1
	lea	myf_First(a3),a0
.C	move.l	(a0),d0
	beq.s	.A
	move.l	d0,a0
	bra.s	.C
.A	move.l	a1,(a0)
	clr.l	myf_Link(a1)
	move.l	a3,myf_Parent(a1)
	move.l	d2,myf_Size(a1)
	add.l	d2,FileSize(a5)
	move.b	#-3,myf_Type(a1)
	move.b	d3,myf_DataOffs(a1)
	clr.b	myf_Locks(a1)
	lea	myf_Name(a1),a0
.E	move.b	(a2)+,(a0)+
	bne.s	.E
	move.l	d3,d1
	move.l	a1,d0
.fail	IFD	DEBUG
	move.l	d0,-(sp)
	lea	myf_Name(a1),a2
	move.l	myf_Size(a1),d0
	DBUG3	txcreat,a2,a1,d0
	move.l	(sp)+,d0
	ENDC
	movem.l	(sp)+,d3/a2-a3
	rts

* Delete file in a1
* ENTRY: a1=file
* EXIT:  d0=success, Z-flag
DeleteObj:
	move.w	#ERROR_OBJECT_NOT_FOUND,dp_Res2+2(a4)
	move.l	myf_Parent(a1),a0
	move.l	myf_First(a0),d0
	sub.l	a0,a0
.C	move.l	a0,d1
	move.l	d0,a0
	tst.l	d0
	beq	DelErr
	move.l	myf_Link(a0),d0
	cmp.l	a1,a0
	bne.s	.C
* ENTRY: a1=file d1=pred.
DeleteObject:
	move.l	d2,-(sp)
	moveq	#0,d0
	move.w	#ERROR_OBJECT_IN_USE,dp_Res2+2(a4)
	tst.b	myf_Locks(a1)
	bne.s	.fail
	tst.b	myf_Type(a1)
	bmi.s	.C
	move.w	#ERROR_DIRECTORY_NOT_EMPTY,dp_Res2+2(a4)
	tst.l	myf_First(a1)	check if dir is empty
	bne.s	.fail
.C	move.l	myf_Link(a1),d2	rearrange links
	move.l	d1,a0
	tst.l	d1
	bne.s	.A
	move.w	#ERROR_OBJECT_WRONG_TYPE,dp_Res2+2(a4)
	move.l	myf_Parent(a1),d1
	beq.s	.fail		do not delete root
	move.l	d1,a0
	lea	myf_First-myf_Link(a0),a0
.A	move.l	d2,myf_Link(a0)
	DBUG1	txdel,a1
	lea	NotifyList(a5),a0
	bra.s	.D
.E	move.l	d0,a0
	cmp.l	myn_Key(a0),a1
	bne.s	.D
	clr.l	myn_Key(a0)	check notifications
.D	move.l	(a0),d0
	bne.s	.E
	moveq	#0,d0		free memory
	move.b	myf_DataOffs(a1),d0
	move.l	myf_Size(a1),d1
	add.l	d1,d0
	sub.l	d1,FileSize(a5)
	bsr	FreeMem
	moveq	#1,d0
.fail	move.l	(sp)+,d2
DelErr	tst.l	d0
	rts

* ENTRY: d0=BPTR parent lock, a0=name (BSTR), d2=access mode
* EXIT:  d0=APTR lock, Z-flag
* Must preserve a3
LocateObject:
	move.w	#ERROR_OBJECT_NOT_FOUND,dp_Res2+2(a4)
	move.l	d0,d3
	bsr	SearchObject
	bne.s	.A
	moveq	#ACCESS_READ,d0
	cmp.l	d0,d2
	bne.s	.C
	tst.b	WriteProtected(a5)
	bne.s	.C
	tst.l	Copyfrom(a5)
	beq.s	.C
	move.l	d3,d0
	bsr	CalcFullName
	bne.s	.A
.C	moveq	#0,d0
	bra	LOfail2
.A	move.l	d0,a2
	tst.b	myf_Type(a2)	hidden ?
	beq.s	.C

* Create lock on file/dir
* ENTRY: a2=file, d2=access mode
* EXIT:  d0=success, Z-flag
CreateLock:
	moveq	#0,d0
	move.w	#ERROR_OBJECT_IN_USE,dp_Res2+2(a4)
	lea	myf_Locks(a2),a0
	moveq	#ACCESS_WRITE,d1
	cmp.l	d1,d2
	bne.s	.A
	tst.b	(a0)
	bne.s	LOfail
	move.b	d1,(a0)
	bra.s	.C
.A	tst.b	(a0)
	bmi.s	LOfail
	addq.b	#1,(a0)
.C	move.w	#ERROR_NO_FREE_STORE,dp_Res2+2(a4)
	move.l	#myl_SIZEOF,d0
	bsr	AllocMem
	beq.s	LOfail
	move.l	d0,a0
	clr.l	myl_Link(a0)
	move.l	a2,myl_Key(a0)
	move.l	d2,myl_Access(a0)
	move.l	MyMsgPort(a5),myl_Task(a0)
	move.l	MyVolumeBPTR(a5),myl_Volume(a0)
	clr.b	myl_Mode(a0)
	addq.l	#1,NumLocks(a5)
LOfail	IFD	DEBUG
	move.l	d0,d1
	lsr.l	#2,d1
	lea	myf_Name(a2),a0
	DBUG3	txlock,a0,d1,d2
	ENDC
LOfail2	tst.l	d0
	rts

* Free lock in a1 (APTR)
FreeLock:
;	move.w	#ERROR_UNLOCK_ERROR,dp_Res2+2(a4)
	IFD	DEBUG
	move.l	a1,d0
	lsr.l	#2,d0
	DBUG1	txulock,d0
	ENDC
	move.l	myl_Key(a1),a0
	tst.b	myf_Locks(a0)
	beq.s	.A
	bmi.s	.D
	subq.b	#1,myf_Locks(a0)
	bra.s	.A
.D	clr.b	myf_Locks(a0)
.A	move.l	#myl_SIZEOF,d0
	bsr	FreeMem
	subq.l	#1,NumLocks(a5)
	rts

*******************************************************

* ENTRY: d0=size
AllocMem:
	add.l	d0,TotalSize(a5)
	move.l	MyMemPool(a5),d1
	beq.s	.A
	move.l	d1,a0
	CALL	AllocPooled
	bra.s	.C
.A	moveq	#1,d1
	CALL	AllocMem
.C	tst.l	d0
	rts

* ENTRY: d0=size, a1=address
FreeMem:
	sub.l	d0,TotalSize(a5)
	move.l	MyMemPool(a5),d1
	beq.s	.A
	move.l	d1,a0
	CALL	FreePooled
	rts
.A	CALL	FreeMem
	rts

* Copy BSTR in a0 to string in a1, d0=maxlength without 0
CopyBSTR2Char:
	add.l	a0,a0
	add.l	a0,a0
	moveq	#0,d1
	move.b	(a0)+,d1
	cmp.l	d0,d1
	bls.s	.C
	exg.l	d0,d1
	bra.s	.C
.A	move.b	(a0)+,(a1)+
.C	dbra	d1,.A
	clr.b	(a1)
	rts

* Copy string in a0 to BSTR in a1, d0=maxlength without 0
* EXIT:  d0=BPTR
CopyChar2BSTR:
	moveq	#-1,d1
	addq.l	#1,a1
.A	addq.l	#1,d1
	cmp.l	d0,d1
	bhs.s	.C
	move.b	(a0)+,(a1)+
	bne.s	.A
	subq.l	#1,a1
.C	clr.b	(a1)
	sub.l	d1,a1
	subq.l	#1,a1
	move.b	d1,(a1)
	move.l	a1,d0
	lsr.l	#2,d0
	rts

CopyChar2Char:
* Copy string in a0 to string in a1, d0=maxlength without 0
.C	move.b	(a0)+,(a1)+
	beq.s	.A
	subq.l	#1,d0
	bne.s	.C
.A	rts


* Same as SearchPath, but creates it if not existent
* ENTRY: TempPath=dirname, d0=lock on dir
* EXIT:  d0=ptr to file, Z-flag, d1=previous file
CreatePath:
	moveq	#1,d1
	bra.s	SearchP

* Same as SearchObject, but deletes hidden files
DelSearchObject
	bsr	SearchObject
	beq.s	.A
	move.l	d0,a1
	tst.b	myf_Type(a1)
	bne	.A
	bsr	DeleteObject	delete hidden file
	moveq	#0,d0
.A	rts

* Look for object with path
* ENTRY: a0=filename (BSTR), d0=lock on dir
* EXIT:  d0=ptr to file, Z-flag, d1=previous file, TempPath=name
SearchObject:
	move.l	d0,-(sp)
	lea	TempPath(a5),a1
	moveq	#MAXPATH-1,d0
	bsr	CopyBSTR2Char
	move.l	(sp)+,d0
* Same as SearchObject, but name already copied to TempPath
SearchPath:	;TempPath=dirname, d0=lock on dir
	moveq	#0,d1
SearchP	movem.l	d2-d7/a2-a4,-(sp)
	move.l	d1,d7
	lea	RootDir(a5),a1
	lea	TempPath(a5),a0
.A	cmp.b	#":",(a0)+	skip volume name
	beq.s	.E
	tst.b	-1(a0)
	bne.s	.A
	lea	TempPath(a5),a0
.D	lsl.l	#2,d0		use root or locked dir
	beq.s	.E
	move.l	d0,a2
	move.l	myl_Key(a2),a1	dir represented by lock
.E
* ENTRY: a0=Name, a1=parent dir; mind SP !
SearchName:
.A	moveq	#0,d0
.D	cmp.b	#"/",(a0)	parent dir when starting with /
	bne.s	.H
	move.l	myf_Parent(a1),d2
	beq.s	.fail
	move.l	d2,a1
	addq.l	#1,a0
	bra.s	.D
.H	tst.b	(a0)		check for empty string
	beq.s	.G
	move.l	a0,a4
	moveq	#0,d3
.C	addq.l	#1,d3		look for / or end
	tst.b	(a4)
	beq.s	.E
	cmp.b	#":",(a4)
	beq.s	.fail
	cmp.b	#"/",(a4)+
	bne.s	.C
.E	tst.b	myf_Type(a1)
	bmi.s	.fail
	bne.s	.J
	tst.l	d7		check for CreatePath
	beq.s	.fail
	move.b	#2,myf_Type(a1)	convert hidden to dir
.J	move.l	a1,d2
	bsr	SearchEntry	search in dir
	bne.s	.F
	tst.l	d7		check for CreatePath
	beq.s	.G
	movem.l	d1-d3/a0/a2-a4,-(sp)
	move.l	d2,a3
	move.l	a0,a2
	move.l	a0,a4
	subq.l	#1,d3
	add.l	d3,a4
	move.b	(a4),d3
	clr.b	(a4)
	moveq	#0,d2
	bsr	CreateNewObj	create new dir
	move.b	d3,(a4)
	move.l	d0,a1
	movem.l	(sp)+,d1-d3/a0/a2-a4
	tst.l	d0
	beq.s	.G
	move.b	#2,myf_Type(a1)
.F	move.l	a4,a0
	bra.s	.A		continue looking for / or end
.G	move.l	a1,d0
.fail	IFD	DEBUG
	lea	TempPath(a5),a0
	moveq	#0,d2
	tst.l	d0
	beq.s	.I
	move.b	myf_Type(a1),d2
.I	DBUG3	txfnd,a0,d0,d2
	ENDC
	movem.l	(sp)+,d2-d7/a2-a4
	tst.l	d0
	rts

* ENTRY: a2=name, a3=parent dir, d2=data size
* EXIT:  d1=offset of data, d0=new file, Z-flag


* Look for object in dir
* ENTRY: a0=file/dir name, a1=ptr to dir, d3=length of name
* EXIT:  a1=ptr to file or 0, Z-flag
SearchEntry:
	moveq	#0,d5
	moveq	#0,d6
	move.l	myf_First(a1),d0
	sub.l	a1,a1
.C	move.l	a1,d1
	move.l	d0,a1
	tst.l	d0
	beq.s	.fail
	move.l	myf_Link(a1),d0
	lea	myf_Name(a1),a2
	move.l	a0,a3
	move.l	d3,d4
	bra.s	.E
.A	move.b	(a2)+,d5
	move.b	CharTable(a5,d5.l),d5
	move.b	(a3)+,d6
	move.b	CharTable(a5,d6.l),d6
	cmp.b	d5,d6
	bne.s	.C
.E	subq.l	#1,d4
	bne.s	.A
	tst.b	(a2)
	bne.s	.C
	IFD	DEBUG
	lea	myf_Name(a1),a3
	DBUG1	txentry,a3
	ENDC
.fail	move.l	a1,d0
	rts

*Splits path with file into path=TempPath and file=TempName
SplitPath
	move.l	a2,-(sp)
	lea	TempPath(a5),a0
	move.l	a0,a1
.A	tst.b	(a0)+
	bne.s	.A
.D	cmp.b	#"/",-(a0)
	beq.s	.C
	cmp.b	#":",(a0)
	beq.s	.C
	cmp.l	a0,a1
	bne.s	.D
	move.l	a0,a1
	bra.s	.G
.C	move.l	a0,a1
	addq.l	#1,a1
.G	lea	TempName(a5),a2
.E	move.b	(a1)+,(a2)+
	bne.s	.E
	cmp.b	#":",(a0)
	bne.s	.F
	addq.l	#1,a0
.F	clr.b	(a0)
	move.l	(sp)+,a2
	IFD	DEBUG
	lea	TempPath(a5),a0
	lea	TempName(a5),a1
	DBUG2	txsplit,a0,a1
	ENDC
	rts

* ENTRY: a1=object
* EXIT:  a0=full name (root name not included) in TempPath
* Only used by CalcFullName
GetFullName:
	move.l	d2,-(sp)
	lea	TempPath+MAXPATH+MAXNAME-1(a5),a0
	clr.b	(a0)
	move.w	#MAXPATH+MAXNAME-1,d2
.A	move.l	myf_Parent(a1),d0
	beq.s	.ok
	lea	myf_Name(a1),a1
	moveq	#-1,d1
.C	addq.l	#1,d1
	tst.b	(a1)+
	bne.s	.C
	subq.l	#1,a1
	sub.w	d1,d2
	bmi.s	.ok
	tst.b	(a0)
	beq.s	.D
	move.b	#"/",-(a0)
	subq.w	#1,d2
	bra.s	.D
.E	move.b	-(a1),-(a0)
.D	dbra	d1,.E
	move.l	d0,a1
	bra.s	.A
.ok	move.l	(sp)+,d2
	rts

* ENTRY: TempPath=name, d0=BPTR parent lock
* EXIT: d0=new file
* Only used by LocateObject
CalcFullName:
	movem.l	d2-d6/a2-a4,-(sp)
	moveq	#0,d4			d4=return code
	bsr	CreatePath
	beq	.fail
	move.l	d0,a1
	move.l	d0,a2
	clr.b	myf_Type(a1)		a2=new hidden file
	bsr	GetFullName
	DBUG1	txfull,a0
	lea	TempPath(a5),a1
	moveq	#MAXPATH-2,d0
	bsr	CopyChar2BSTR
	move.l	d0,d5			d5=BSTR full name

	move.l	#fib_SIZEOF+fh_SIZEOF,d0
	bsr	AllocMem
	beq	.fail
	move.l	d0,a3			a3=File info block
	lea	fib_SIZEOF(a3),a4	a4=file handle

	move.l	Copyfrom(a5),a0
	move.l	dol_Lock(a0),d1
	move.l	dol_List(a0),d6	
	bra.s	.D
.C	tst.l	d6
	beq	.fail2
	move.l	d6,a0
	move.l	(a0),d6		al_Next
	move.l	4(a0),d1	al_Lock
.D	move.l	d1,CopyfromLock(a5)
	move.l	d1,a0
	add.l	a0,a0
	add.l	a0,a0
	move.l	fl_Task(a0),CopyfromPort(a5)
	move.l	d5,d2
	moveq	#ACCESS_READ,d3
	moveq	#ACTION_LOCATE_OBJECT,d0
	bsr	DoPacket
	beq	.C

	move.l	d0,d3			d3=lock on file
	move.l	d3,d1
	move.l	a3,d2
	lsr.l	#2,d2
	moveq	#ACTION_EXAMINE_OBJECT,d0
	bsr	DoPacket
	move.l	d0,-(sp)
	move.l	d3,d1
	moveq	#ACTION_FREE_LOCK,d0
	bsr	DoPacket
	move.l	(sp)+,d0
	beq.s	.fail2
	tst.l	fib_DirEntryType(a3)
	bmi.s	.A
	move.b	#2,myf_Type(a2)		turn hidden into dir
	move.l	a2,d4
	bra.s	.fail2

.A	move.l	a4,d1
	lsr.l	#2,d1
	move.l	CopyfromLock(a5),d2
	move.l	d5,d3
	move.l	#ACTION_FINDINPUT,d0
	bsr	DoPacket
	beq.s	.fail2
	movem.l	a2/a3,-(sp)
	move.l	fib_Size(a3),d2
	move.l	myf_Parent(a2),a3
	lea	myf_Name(a2),a2
	bsr	CreateNewObject
	movem.l	(sp)+,a2/a3
	beq.s	.fail3
	move.l	d0,d2
	add.l	d1,d2
	move.l	a2,a1
	move.l	d0,a2
	bsr	DeleteObj
	beq.s	.fail3
	move.l	fh_Arg1(a4),a4
	move.l	a4,d1
	move.l	fib_Size(a3),d3
	moveq	#ACTION_READ,d0
	bsr	DoPacket
	bsr	UpdateNotify
.fail3	move.l	a4,d1
	move.l	#ACTION_END,d0
	bsr	DoPacket
	move.l	a2,d4
.fail2	move.l	a3,a1
	move.l	#fib_SIZEOF+fh_SIZEOF,d0
	bsr	FreeMem
.fail	move.l	d4,d0
	movem.l	(sp)+,d2-d6/a2-a4
	rts

*******************************************************

	IFD	DEBUG
RawHook	move.l	a6,-(sp)
	move.l	4.w,a6
	jsr	_LVORawPutChar(a6)
	move.l	(sp)+,a6
	rts

wait_c:
	movem.l	d0-d1/a0-a1,-(sp)
	moveq	#0,d0
	moveq	#0,d1
	bset	#12,d1
	jsr	_LVOSetSignal(a6)
	moveq	#0,d0
	bset	#12,d0
	jsr	_LVOWait(a6)	wait for CTRL-C
	movem.l	(sp)+,d0-d1/a0-a1
	rts

	IFD	VERBOSE
txstart	dc.b	"Handler started, A5=$%lx.",10,0
txend	dc.b	"Handler ended, FileSize=%ld, TotalSize=%ld.",10,0
txcopy	dc.b	"Copyfrom=$%lx.",10,0
txpack	dc.b	"Type=%ld Arg1=$%lx Arg2=$%lx Arg3=$%lx, Task=%s.",10,0
txres	dc.b	"Result1=$%lx, Result2=%ld.",10,0
txpkt	dc.b	"  Packet=$%lx, type=%ld, res=$%lx, err=%ld.",10,0
txerr1	dc.b	"  %ld: Unknown Action.",10,0

txopeno	dc.b	"  Oldopen lock=$%lx.",10,0
txopenn	dc.b	"  Newopen lock=$%lx.",10,0
txcreat	dc.b	"  Created file %s=$%lx size=%ld.",10,0
txread	dc.b	"  Read %ld of %ld bytes, pos=%ld.",10,0
txwrite	dc.b	"  Wrote %ld bytes, pos=%ld, size=%ld.",10,0
txwins	dc.b	"  Inserted %ld bytes at %ld.",10,0
txseek	dc.b	"  Seeked, filepos=%ld.",10,0
txdel	dc.b	"  Deleted $%lx.",10,0

txlock	dc.b	"  Locked %s=$%lx mode %ld.",10,0
txulock	dc.b	"  Unlocked $%lx.",10,0
txexam	dc.b	"  Examined file=$%lx.",10,0
txexnx	dc.b	"  Examined next file=$%lx.",10,0
txfnd	dc.b	"    Found %s=$%lx type=%ld.",10,0
txentry	dc.b	"    Found entry %s.",10,0
txsplit	dc.b	"    Splitted ->%s,%s.",10,0
txfull	dc.b	"    Full name: %s.",10,0

txanoti	dc.b	"  Added noti $%lx->$%lx on %s key=$%lx.",10,0
txrnoti	dc.b	"  Removed noti $%lx->$%lx.",10,0
txcnoti	dc.b	"  Checking noti on %s.",10,0
txunoti	dc.b	"    Updated noti on %s key=$%lx.",10,0
txsnoti	dc.b	"    Sent signal to %s for %s.",10,0
txmnoti	dc.b	"    Sent message $%lx to %s for %s.",10,0
txgnoti	dc.b	"    Got message $%lx.",10,0
	ENDC

	IFND	VERBOSE
txstart	dc.b	"Handler started, A5=$%lx.",10,0
txend	dc.b	"Handler ended, FileSize=%ld, TotalSize=%ld.",10,0
txcopy	dc.b	"Copyfrom=$%lx.",10,0
txpack	dc.b	"Type=%ld Arg1=$%lx Arg2=$%lx Arg3=$%lx, Task=%s.",10,0
txres	dc.b	"Result1=$%lx, Result2=%ld.",10,0
txpkt	dc.b	0;"  Packet=$%lx, type=%ld, res=$%lx, err=%ld.",10,0
txerr1	dc.b	"  %ld: Unknown Action.",10,0

txopeno	dc.b	0;"  Oldopen lock=$%lx.",10,0
txopenn	dc.b	0;"  Newopen lock=$%lx.",10,0
txcreat	dc.b	"  Created file %s=$%lx size=%ld.",10,0
txread	dc.b	0;"  Read %ld of %ld bytes, pos=%ld.",10,0
txwrite	dc.b	0;"  Wrote %ld bytes, pos=%ld, size=%ld.",10,0
txwins	dc.b	0;"  Inserted %ld bytes at %ld.",10,0
txseek	dc.b	0;"  Seeked, filepos=%ld.",10,0
txdel	dc.b	"  Deleted $%lx.",10,0

txlock	dc.b	"  Locked %s=$%lx mode %ld.",10,0
txulock	dc.b	"  Unlocked $%lx.",10,0
txexam	dc.b	0;"  Examined file=$%lx.",10,0
txexnx	dc.b	0;"  Examined next file=$%lx.",10,0
txfnd	dc.b	0;"    Found %s=$%lx type=%ld.",10,0
txentry	dc.b	0;"    Found entry %s.",10,0
txsplit	dc.b	0;"    Splitted ->%s,%s.",10,0
txfull	dc.b	0;"    Full name: %s.",10,0

txanoti	dc.b	"  Added noti $%lx->$%lx on %s key=$%lx.",10,0
txrnoti	dc.b	"  Removed noti $%lx->$%lx.",10,0
txcnoti	dc.b	0;"  Checking noti on %s.",10,0
txunoti	dc.b	0;"    Updated noti on %s key=$%lx.",10,0
txsnoti	dc.b	0;"    Sent signal to %s for %s.",10,0
txmnoti	dc.b	0;"    Sent message $%lx to %s for %s.",10,0
txgnoti	dc.b	0;"    Got message $%lx.",10,0
	ENDC

	ENDC

