*************************
*   HappyENV-Handler	*
*     1.0 05.06.97	*
*  (C) Martin Gierich	*
*************************


* Do not use this source code or parts of it in other programs !
* See documentation about Copyright&Disclaimer.
* Sorry about the not so well commented source.


* Switches for options, enabled if label is defined,
* disabled if semicolon is put in front of it.

;DEBUG		= 1	;allow debugging output via sushi (RawPutChar)
;VERBOSE	= 1	;verbose debug output
;EXPAND		= 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	dos/rdargs.i
	INCLUDE debug.i

* macro for calling OS routines

CALL	MACRO
	jsr	_LVO\1(a6)
	ENDM

* other macros
* compare both operands and store minimum in the right one
* third argument is label name

MIN	MACRO
	cmp.l	\2,\1
	bhs.s	.\3
	move.l	\1,\2
.\3	nop
	ENDM

* miscellaneous definitions

LF		= 10
mn_Node		= 0
lib_Version	= 20
_LVOToUpper	= -174
_LVOEasyRequestArgs = -588
DOS_TRUE	= -1
DOS_FALSE	= 0
MEMF_CLEAR	= $10000
MAXPATH		= 120
MAXNAME		= 32
BLOCKSIZE	= 5000

* EasyRequest structure (Intuition)
		RSRESET
es_StructSize	RS.L	1
es_Flags	RS.L	1
es_Title	RS.L	1
es_TextFormat	RS.L	1
es_GadgetFormat	RS.L	1
es_SIZEOF	RS.W	0


* 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	0	;path/file name (dynamic)

* 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 (root: 0)
myf_First	RS.L	0	;dir:  points to first entry
myf_Size	RS.L	1	;file: size of filedata
myf_Type	RS.B	1	;bit7: dir/file, 6:hidden, 5:copied,
				;4:notify
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
IntuiBase	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
ReqStruct	RS.B	es_SIZEOF
FormatArgs	RS.L	2
StupVolname	RS.L	1
StupIcon	RS.B	1
StupNocopy	RS.B	1
StupNoreq	RS.B	1
StupExpand	RS.B	1
My_SIZEOF	RS.W	0

MyPkt		= MyPacket+sp_Pkt

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

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

* common register usage:
* 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)
;	clr.b	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

inireq:	lea	intuiname(pc),a1	;init "unknown packet" requester
	moveq	#36,d0
	CALL	OpenLibrary
	move.l	d0,IntuiBase(a5)
	beq.s	.A
	lea	ReqStruct(a5),a0
	moveq	#es_SIZEOF,d0
	move.l	d0,(a0)+
	clr.l	(a0)+
	lea	reqtitle(pc),a1
	move.l	a1,(a0)+
	clr.l	(a0)+
	lea	reqbutton(pc),a1
	move.l	a1,(a0)+
.A

args:	move.l	MyDeviceNode(a5),a1
	move.l	dn_Startup(a1),a0
	clr.l	dn_Startup(a1)
	move.l	a0,d0
	beq	.A
	lea	TempPath(a5),a1
	move.l	a1,a2
	moveq	#MAXPATH-1,d0
	bsr	CopyBSTR2Char
	moveq	#DOS_RDARGS,d1
	moveq	#0,d2
	move.l	DosBase(a5),a6
	CALL	AllocDosObject
	move.l	d0,d3
	beq	.A
	move.l	a2,a0
.D	move.b	(a0)+,d0
	beq.s	.C
	cmp.b	#"_",d0
	bne.s	.D
	move.b	#" ",-1(a0)
	bra.s	.D
.C	move.b	#LF,-1(a0)
	clr.b	(a0)
	sub.l	a2,a0
	lea	TempName(a5),a3
	move.l	a3,d2			;Argument-Array
	clr.l	(a3)+			;clear it
	clr.l	(a3)+
	clr.l	(a3)+
	clr.l	(a3)
	move.l	d2,a3
	move.l	d3,a1			;Rd-Args-Struct
	move.l	a2,(a1)+		;CSource.Buffer
	move.l	a0,(a1)			;CSource.Length
	lea	template(pc),a0
	move.l	a0,d1			;Template
	CALL	ReadArgs		;process Startup line
	DBUG4	txargs,(a3),4(a3),8(a3),12(a3)
	move.l	d0,d2
	bne.s	.E
	bsr	RequestReadArgs
	bra.s	.A
.E	move.l	(a3)+,d0
	beq.s	.G
	move.l	d0,a0
	lea	VolumeName(a5),a1
	moveq	#MAXNAME-2,d0
	bsr	CopyChar2BSTR
	move.l	d0,StupVolname(a5)
.G	lea	StupIcon(a5),a0
	move.l	(a3)+,d0
	move.b	d0,(a0)+
	move.l	(a3)+,d0
	move.b	d0,(a0)+
	move.l	(a3)+,d0
	move.b	d0,(a0)+
	move.l	d2,d1
	CALL	FreeArgs
	moveq	#DOS_RDARGS,d1
	move.l	d3,d2
	CALL	FreeDosObject
.A	move.l	4.w,a6

volnod:	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	volname1(pc),a0
	tst.b	StupIcon(a5)
	beq.s	.A
	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)
	lea	volname2(pc),a0
.A	move.l	StupVolname(a5),d0
	bne.s	.C
	lea	VolumeName(a5),a1
	moveq	#MAXNAME-2,d0
	bsr	CopyChar2BSTR
.C	move.l	d0,dl_Name(a2)

upconv:	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

auto:	tst.b	StupNocopy(a5)		;init autocopy
	bne.s	.A
	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

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
	bsr	RequestUnknown
	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)		;jump into subroutine to process packet
				;***
.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
	tst.b	StupIcon(a5)
	beq.s	.A
	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)

.A	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)
	DBUG3	txend,FileSize(a5),TotalSize(a5),NumLocks(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

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

* table for branching from main to subroutine depending on the
* current packet

JumpTable:
	dc.w	ACTION_NIL,NoAction-start
	dc.w	ACTION_SET_PROTECT,Unsupported-start
	dc.w	ACTION_SET_COMMENT,Unsupported-start
	dc.w	ACTION_SET_DATE,Unsupported-start
	dc.w	ACTION_INHIBIT,Unsupported-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,AOpenReadWrite-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_ALL,Unsupported-start
	dc.w	ACTION_EXAMINE_FH,AExamineFH-start
	dc.w	ACTION_EXAMINE_ALL_END,Unsupported-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


* strings

volname1	dc.b	"Env",0
volname2	dc.b	"Environment",0
intuiname	dc.b	"intuition.library",0
reqtitle	dc.b	"HappyENV warning:",0
requnknown	dc.b	"Task %s",LF,"uses packet %ld",0
reqreadargs	dc.b	"Bad startup arguments",0
reqbutton	dc.b	"Ok",0
version		dc.b	"$VER: HappyENV-Handler 1.0 (05.06.97)",LF,0
dosname		dc.b	"dos.library",0
utilname	dc.b	"utility.library",0
sysdisk		dc.b	"ENVARC",0
template	dc.b	"VOLNAME/K,ICON/S,NOCOPY/S,NOREQ/S",0
		IFD	EXPAND
prefstx		dc.b	"prefs",0
configtx	dc.b	"config",0
		ENDC
		even

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

* Init to-upper-conversion table which allows
* quick case independent compares
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

* Display requester for unknown packets
RequestUnknown:
	tst.b	StupNoreq(a5)
	bne.s	.A
	move.l	IntuiBase(a5),a6
	move.l	a6,d0
	beq.s	.A
	lea	ReqStruct(a5),a1
	lea	requnknown(pc),a0
	move.l	a0,12(a1)
	sub.l	a2,a2
	lea	FormatArgs(a5),a3
	move.l	dp_Type(a4),4(a3)
	move.l	dp_Port(a4),a0
	move.l	MP_SIGTASK(a0),a0
	move.l	LN_NAME(a0),(a3)
	sub.l	a0,a0
	CALL	EasyRequestArgs
	move.l	4.w,a6
.A	rts

* Display requester for bad startup arguments
RequestReadArgs:
	move.l	IntuiBase(a5),a6
	move.l	a6,d0
	beq.s	.A
	lea	ReqStruct(a5),a1
	lea	reqreadargs(pc),a0
	move.l	a0,12(a1)
	sub.l	a2,a2
	sub.l	a3,a3
	sub.l	a0,a0
	CALL	EasyRequestArgs
	move.l	4.w,a6
.A	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)
* More general reply packet
* 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

* Reply all packets that are waiting to be processed (for exit)
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

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

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


* Following there are all subroutines to process the individual packets
* It starts with some general purpose and Filehandle handling ones.

* No action will be performed
NoAction:
	moveq	#DOS_TRUE,d0
	move.l	d0,dp_Res1(a4)
	rts

* For unsupported packets without showing a requester
Unsupported:
	DBUG1	txerr1,dp_Type(a4)
	move.w	#ERROR_ACTION_NOT_KNOWN,dp_Res2+2(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	

AOpenReadWrite:
	move.l	dp_Arg3(a4),a0
	move.l	dp_Arg2(a4),d0
	moveq	#ACCESS_READ,d2
	bsr	LocateObject
	bne.s	OpnOld
	bra.s	AOpenNewfile

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	;label used by AOpenReadWrite and AFHFromLock
	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	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)
	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)
	moveq	#DOS_TRUE,d0
	move.l	d0,dp_Res1(a4)
	DBUG1	txopenn,fh_Arg1(a3)
.fail	rts

ACloseFile:
	move.l	dp_Arg1(a4),a1
	tst.b	myl_Mode(a1)
	bmi.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
	bsr	CopyBlocksToMem
	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

* Copy all blocks of a filehandle to memory
* ENTRY: a2=lock, a3=destination memory
* EXIT: nothing (some registers changed)
* USED BY: ACloseFile, ASetFileSize
CopyBlocksToMem:
	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	rts

AWriteFile:
	moveq	#-1,d0
	move.l	d0,dp_Res1(a4)
	move.w	#ERROR_DISK_WRITE_PROTECTED,dp_Res2+2(a4)
	tst.b	WriteProtected(a5)
	bne	.fail
	move.l	dp_Arg1(a4),a2		;lock
	move.l	dp_Arg2(a4),a3		;buffer
	move.l	dp_Arg3(a4),d3		;length

	bsr	ReadToWriteMode
	beq	.fail
.F	move.l	d3,d2
	move.l	myl_Block(a2),d0
	beq.s	.E
	move.l	d0,a1
	move.l	4(a1),d0
	sub.l	myl_BlockPos(a2),d0
	beq.s	.C
	bmi.s	.C
	MIN	d0,d2,G
.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.s	.F	
	
.E	bsr	AppendNewBlock
	beq.s	.fail
	clr.w	dp_Res2+2(a4)
	move.l	a3,a0
	move.l	d3,d0
	CALL	CopyMem
	add.l	d3,myl_Pos(a2)
	move.l	d3,myl_BlockPos(a2)
.ok	move.l	dp_Arg3(a4),dp_Res1(a4)
	DBUG3	txwrite,dp_Arg3(a4),myl_Pos(a2),myl_Size(a2)
.fail	rts

ASetFileSize:
	moveq	#-1,d0
	move.l	d0,dp_Res1(a4)
	move.w	#ERROR_DISK_WRITE_PROTECTED,dp_Res2+2(a4)
	tst.b	WriteProtected(a5)
	bne	.fail
	move.w	#ERROR_SEEK_ERROR,dp_Res2+2(a4)
	move.l	dp_Arg1(a4),a2		;a2=lock
	move.l	dp_Arg2(a4),d3		;d3=position to truncate
	move.l	dp_Arg3(a4),d2		;d2=mode
	move.l	myl_Size(a2),d4		;d4=old size
	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,d3
	bra.s	.E
.C	moveq	#OFFSET_CURRENT,d0
	cmp.l	d0,d2
	bne	.fail
	add.l	myl_Pos(a2),d3
.E	DBUG2	txsize,myl_Key(a2),d4,d3
	tst.l	d3			;d3=new size
	bmi	.fail
	cmp.l	d4,d3
	beq.s	.ok			;size will not change
	bhi.s	.A			;append some data

	move.l	d3,myl_Size(a2)		;truncate some data
	MIN	d3,myl_Pos(a2),F
	bsr	ReadToWriteMode
	beq.s	.fail
	cmp.b	#1,d0
	beq.s	.ok
	move.l	myl_Pos(a2),myl_BlockPos(a2)
	move.l	d3,d0
	beq.s	.D
	bsr	CreateNewBlock
	beq.s	.fail
.D	move.l	myl_Start(a2),d4
	move.l	d0,myl_Block(a2)
	move.l	d0,myl_Start(a2)
	move.l	a1,a3
.J	tst.l	d4
	beq.s	.ok
	move.l	d4,-(sp)
	move.l	d4,a0
	move.l	(a0)+,d4
	move.l	(a0)+,d2
	cmp.l	d2,d3
	bls.s	.G
	move.l	d2,d0
	sub.l	d2,d3
	bra.s	.H
.G	move.l	d3,d0
	beq.s	.I
	moveq	#0,d3
.H	move.l	a3,a1
	CALL	CopyMem
.I	add.l	d2,a3
	move.l	d2,d0
	addq.l	#8,d0
	move.l	(sp)+,a1
	bsr	FreeMem
	bra.s	.J

.A	bsr	ReadToWriteMode		;append some data
	beq.s	.fail
	sub.l	d4,d3
	bsr	AppendNewBlock
	beq.s	.fail
.ok	move.l	myl_Size(a2),dp_Res1(a4)
.fail	rts


* Convert Lock from Read to Write mode
* ENTRY: a2=lock
* EXIT:  d0,Z=success (0=fail, 1=changed, 2=not changed)
* USED BY: AWriteFile, ASetFileSize
ReadToWriteMode:
	moveq	#2,d0
	tst.b	myl_Mode(a2)
	bmi.s	.ok
	move.w	#ERROR_WRITE_PROTECTED,dp_Res2+2(a4)
	move.l	myl_Key(a2),a0
	cmp.b	#1,myf_Locks(a0)
	bhi.s	.fail
	move.l	myl_Size(a2),d0
	beq.s	.A
	bsr	CreateNewBlock
	beq.s	.fail
.A	move.l	d0,myl_Block(a2)
	move.l	d0,myl_Start(a2)
	move.l	myl_Pos(a2),myl_BlockPos(a2)
	move.b	#-1,myl_Mode(a2)
	move.l	myl_Key(a2),a0
	move.b	#-1,myf_Locks(a0)
	move.l	myl_Data(a2),a0
	move.l	myl_Size(a2),d0
	beq.s	.C
	CALL	CopyMem
.C	DBUG2	txchng,myl_Key(a2),myl_Pos(a2),myl_Size(a2)
	moveq	#1,d0
.ok	rts
.fail	moveq	#0,d0
	rts

* Create and append a new block as last one to block list
* ENTRY: d3=size, a2=lock
* EXIT:  d0,Z=success, a1=newblock+8
* USED BY: AWriteFile, ASetFileSize
AppendNewBlock:
	move.l	d3,d0
	bsr	CreateNewBlock
	beq.s	.fail
	add.l	d3,myl_Size(a2)
	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	(a0),d1			;look for end of blocks
	beq.s	.C			; for SetFileSize
	move.l	d1,a0
	bra.s	.A
.C	move.l	d0,(a0)			;insert new block as last
	moveq	#1,d0
.fail	rts

* Allocates memory for a new block
* ENTRY: d0=size
* EXIT:  d0=block , a1=block+8
* USED BY: AppendNewBlock, ReadToWriteMode, ASetFileSIze
CreateNewBlock:
	move.w	#ERROR_DISK_FULL,dp_Res2+2(a4)
	move.l	d0,-(sp)
	addq.l	#8,d0
	bsr	AllocMem
	beq.s	.fail
	move.l	d0,a1
	clr.l	(a1)+
	move.l	(sp),(a1)+
.fail	addq.l	#4,sp
	tst.l	d0
	rts

AReadFile:
	move.l	dp_Arg1(a4),a2		;lock
	move.l	dp_Arg2(a4),a3		;buffer
	move.l	myl_Size(a2),d0
	move.l	myl_Pos(a2),a0
	sub.l	a0,d0
	move.l	dp_Arg3(a4),d3		;length
	MIN	d0,d3,G
	clr.w	dp_Res2+2(a4)
	DBUG3	txread,d3,dp_Arg3(a4),myl_Pos(a2)
	add.l	d3,myl_Pos(a2)
	move.l	d3,dp_Res1(a4)
	beq.s	.ok
	tst.b	myl_Mode(a2)
	bpl.s	.E

.F	move.l	d3,d2
	move.l	myl_Block(a2),a0
	move.l	4(a0),d0
	sub.l	myl_BlockPos(a2),d0
	beq.s	.C
	bmi.s	.C
	MIN	d0,d2,D
	addq.l	#8,a0
	add.l	myl_BlockPos(a2),a0
	move.l	a3,a1
	move.l	d2,d0
	CALL	CopyMem
	add.l	d2,a3
	add.l	d2,myl_BlockPos(a2)
	sub.l	d2,d3
	beq.s	.ok
	bra.s	.F
.C	move.l	(a1),d0
	beq.s	.ok
	move.l	d0,myl_Block(a2)
	clr.l	myl_BlockPos(a2)
	bra	.F

.E	move.l	myl_Data(a2),d0
	add.l	d0,a0
	move.l	a3,a1
	move.l	d3,d0
	CALL	CopyMem
.ok	rts

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

	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	tst.b	myl_Mode(a2)	;label not used globally
	bpl.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

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

* Here are subroutines for packets that deal with Locks. 

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		;label not used globally
	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		;label not used globally
	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:
	tst.b	StupIcon(a5)
	bne	Unsupported
	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	Exammi

AExamineObject:
	move.l	dp_Arg1(a4),a0
	add.l	a0,a0
	add.l	a0,a0
Exammi	move.l	myl_Key(a0),a0	;label not used globally
	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
* Fill FileInfoBlock (fib) with infos about the object
* Used by AExamineFH, AExamineObject and AExamineNext
* ENTRY: a0=file, a1=fib
ExamineObject:
	moveq	#1,d0
	tst.l	myf_Parent(a0)
	beq.s	.C			;rootdir ?
	IFD	DEBUG
	btst	#6,myf_Type(a0)
	beq.s	.D			;hidden file ?
	moveq	#-3,d0
	bra.s	.C
.D	ENDC
	moveq	#-3,d0
	tst.b	myf_Type(a0)
	bmi.s	.C			;file ?
	moveq	#2,d0			;dir
.C	moveq	#0,d1
	move.l	d0,fib_DirEntryType(a1)
	move.l	d0,fib_EntryType(a1)
	bpl.s	.A
	move.l	myf_Size(a0),d1		;no file no size
.A	move.l	a0,fib_DiskKey(a1)
	move.l	d1,fib_Size(a1)		;calc size
	add.l	#1023,d1
	lsr.l	#8,d1
	lsr.l	#2,d1
	move.l	d1,fib_NumBlocks(a1)
	moveq	#2,d0
	move.b	myf_Type(a0),d1
	btst	#5,d1			;copied ? -> A
	beq.s	.F
	bset	#4,d0
.F	btst	#4,d1			;notify ? -> P
	beq.s	.G
	bset	#5,d0
.G	IFD	DEBUG
	btst	#6,d1			;hidden ? -> H
	beq.s	.J
	bset	#7,d0
.J	tst.b	myf_Locks(a0)
	beq.s	.H
	bmi.s	.I
	bset	#2,d0			;read-locked ?  -> no W
	bra.s	.H
.I	bset	#3,d0			;write-locked ? -> no R
.H	ENDC
	move.l	d0,fib_Protection(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
	DBUG1	txexan,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
	btst	#6,myf_Type(a0)
	bne.s	.A
	ENDC
	bra	ExamineObject
.fail	rts

ADiskInfo1:
	move.l	dp_Arg1(a4),a0
	bra.s	DiskInfo
ADiskInfo2:
	move.l	dp_Arg2(a4),a0
* ENTRY: a0=buffer (BPTR)
DiskInfo:			;label not used globally
	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
	clr.b	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

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

* Here are subroutines that deal with Locks and Filehandles

AFHfromLock:
	move.w	#ERROR_OBJECT_WRONG_TYPE,dp_Res2+2(a4)
	move.l	dp_Arg2(a4),d0
	beq.s	.fail
	lsl.l	#2,d0
	move.l	d0,a0
	move.l	myl_Key(a0),a0
	tst.b	myf_Type(a0)		;do not open dirs
	bmi	OpnOld
.fail	rts

AChangeMode:
	move.w	#ERROR_OBJECT_IN_USE,dp_Res2+2(a4)
	move.l	dp_Arg1(a4),d0
	move.l	dp_Arg2(a4),a2
	moveq	#CHANGE_FH,d1
	cmp.l	d0,d1
	bne.s	.A
	move.l	dp_Arg1(a4),a3
	add.l	a3,a3
	add.l	a3,a3
	move.l	fh_Arg1(a3),d0
	beq.s	.fail
	move.l	d0,a2
	bra.s	.C
.A	moveq	#CHANGE_LOCK,d1
	cmp.l	d0,d1
	bne.s	.fail
.C	move.l	myl_Key(a2),a0
	move.b	myf_Locks(a0),d0
	move.l	dp_Arg3(a4),d2
	moveq	#ACCESS_WRITE,d1
	cmp.l	d1,d2
	bne.s	.D
	cmp.b	d0,d1
	beq.s	.ok
	cmp.b	#1,d0
	bne.s	.fail
	move.b	d1,myf_Locks(a0)
	bra.s	.ok
.D	cmp.b	d0,d1
	bne.s	.E
	tst.l	myl_Start(a2)
	bne.s	.fail
	move.b	#1,myf_Locks(a0)
.E	moveq	#ACCESS_READ,d1
.ok	move.l	d1,myl_Access(a2)
	moveq	#DOS_TRUE,d0
	move.l	d0,dp_Res1(a4)
.fail	rts

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

* Here are subroutines for notification support

AAddNotify:
	move.w	#ERROR_NO_FREE_STORE,dp_Res2+2(a4)
	move.l	dp_Arg1(a4),a3
	moveq	#myn_Name,d0
	move.l	nr_FullName(a3),a0
.C	addq.l	#1,d0
	tst.b	(a0)+
	bne.s	.C
	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
.D	move.b	(a0)+,(a1)+
	bne.s	.D
	bsr	UpNoti
	IFD	DEBUG
	lea	myn_Name(a2),a0
	DBUG4	txanoti,a2,a3,a0,d0
	ENDC
	move.l	nr_Flags(a3),d1
	btst	#NRB_NOTIFY_INITIAL,d1	;initial notify ?
	beq.s	.A
	tst.l	d0
	beq.s	.A
	move.l	d0,a0
	btst	#6,myf_Type(a0)		;file really exists ?
	bne.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_Key(a1),d0
	beq.s	.D
	move.l	d0,a0
	bclr	#4,myf_Type(a0)
.D	moveq	#myn_Name,d0
	lea	myn_Name(a1),a0
.C	addq.l	#1,d0
	tst.b	(a0)+
	bne.s	.C
	bsr	FreeMem
	moveq	#DOS_TRUE,d0
	move.l	d0,dp_Res1(a4)
.fail	rts

* Update myn_Key of notification list, mainly used by CheckNotify
* 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
	bsr.s	UpNoti
	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

* Subroutine used by UpdateNotify and AddNotify
UpNoti	lea	myn_Name(a2),a0
	lea	TempPath(a5),a1
	moveq	#MAXPATH-1,d0
	bsr	CopyChar2Char
	moveq	#0,d0
	bsr	SearchPath
	bne.s	.A
	moveq	#0,d0
	bsr	CalcFullName
.A	move.l	d0,myn_Key(a2)
	beq.s	.D
	move.l	d0,a0
	bset	#4,myf_Type(a0)
.D	rts

* Update notification list, check it for file/dir and parent dir
* and notify them.
* 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

* Check notification list for file/dir and parent dir and notify them.
* ENTRY: a0=file
NotifyObject:
	bsr	NotifyObj
	move.l	myf_Parent(a0),d1
	move.l	d1,a0
	beq.s	.E
	bsr	NotifyObj
.E	rts

* Notify object in a0, only used by NotifyObject
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 messages
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

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

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

* Following there are support subroutines for creating and deleting
* objects and Locks.

* Create a new file/dir
* ENTRY: a2=name, a3=parent dir, d2=data size
* EXIT:  d1=offset of data, d0=new file, Z-flag for success
CreateNewObject:
	move.w	#ERROR_DISK_FULL,dp_Res2+2(a4)
CreateNewObj:		;label used by SearchPath and CalcFullName
	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	#$80,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/dir in a1, no pred. known
* 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

* Delete file/dir in a1 with pred. known
* 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		;label not used globally
	rts

* Create lock on file/dir given by name
* Must preserve a3
* ENTRY: d0=BPTR parent lock, a0=name (BSTR), d2=access mode
* EXIT:  d0=APTR lock, Z-flag
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
	move.l	d3,d0
	bsr	CalcFullName
	bne.s	.A
.C	moveq	#0,d0
	bra	LOfail2
.A	move.l	d0,a2
	btst	#6,myf_Type(a2)		;hidden ?
	bne.s	.C

* Create lock on file/dir given by key
* 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)
	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)
	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
* ENTRY: a1=lock (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

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

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

* Support routines for lower level memory management

* ENTRY: d0=size
* EXIT:  d0=memory
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
	MIN	d0,d1,D
	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


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

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

* Subroutines for path string handling following

* Same as SearchObject, but deletes hidden files
* ENTRY: a0=filename (BSTR), d0=lock on dir
* EXIT:  d0=ptr to file, Z-flag, d1=previous file, TempPath=name
DelSearchObject
	bsr	SearchObject
	beq.s	.A
	move.l	d0,a1
	btst	#6,myf_Type(a1)
	beq.s	.A
	bsr	DeleteObject		;delete hidden file
	moveq	#0,d0
.A	tst.l	d0
	rts

* Same as SearchPath, but creates the path 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

* 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 is already copied to TempPath
* ENTRY: TempPath=dirname, d0=lock on dir
* EXIT:  d0=ptr to file, Z-flag, d1=previous file
SearchPath:
	moveq	#0,d1
SearchP	movem.l	d2-d7/a2-a4,-(sp)	;label not used globally
	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
* label not used
expand	IFD	EXPAND
	tst.b	StupExpand(a5)		;expand env:appname.prefs to
	beq	.A
	tst.l	myf_Parent(a1)		;env:appname/appname.prefs
	bne	.A			;not in rootdir ?
	move.l	a0,a4
	sub.l	a2,a2
.C	move.b	(a4)+,d0
	beq.s	.D
	cmp.b	#"/",d0			;check for "/"
	beq	.A
	cmp.b	#".",d0
	bne.s	.C
	move.l	a4,a2			;remember "."
	bra.s	.C
.D	move.l	a2,d0
	beq.s	.A
	sub.l	a0,d0
	lea	TempPath(a5),a3
	sub.l	a3,a4
	add.l	a4,d0
	cmp.l	#MAXPATH-1,d0
	bhs.s	.A
	move.l	a2,a4
	lea	prefstx(pc),a3		;ends in ".prefs" ?
.cmp1	move.b	(a4)+,d0
	cmp.b	(a3)+,d0
	bne.s	.F
	tst.b	d0
	bne.s	.cmp1
	bra.s	.G
.F	move.l	a2,a4
	lea	configtx(pc),a3		;ends in ".config" ?
.cmp2	move.b	(a4)+,d0
	cmp.b	(a3)+,d0
	bne.s	.A
	tst.b	d0
	bne.s	.cmp2

.G	tst.b	(a4)+
	bne.s	.G
	move.l	a4,a3
	sub.l	a0,a3
	add.l	a2,a3
	move.l	a4,d0
	sub.l	a0,d0
	bra.s	.I
.H	move.b	-(a4),-(a3)
.I	dbra	d0,.H
	move.b	#"/",-1(a2)
	DBUG1	txexp,a0

;	move.b	#"/",-1(a2)		;insert "/" instead of "."
;	move.l	a0,a3
;.H	move.b	(a3)+,d0		;copy first part of filename
;	move.b	d0,(a2)+
;	cmp.b	#"/",d0
;	bne.s	.H
;	move.b	#".",-1(a2)		;append ".prefs"
;	lea	prefstx(pc),a3
;.I	move.b	(a3)+,(a2)+
;	bne.s	.I
;	DBUG1	txexp,a0
.A	ENDC
* end of expand

* label not used
* ENTRY: a0=Name, a1=parent dir; mind SP !
* EXIT:  d0=ptr to file, Z-flag, d1=previous file
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	move.b	myf_Type(a1),d2
	bmi.s	.fail
	btst	#6,d2
	beq.s	.J
	tst.l	d7			;check for CreatePath
	beq.s	.fail
	clr.b	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
	clr.b	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

* 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
* ENRTY: TempPath=file with path
* EXIT:  TempPath=path, TempName=file
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

* Evaluate full path name of object
* Only used by CalcFullName
* ENTRY: a1=object
* EXIT:  a0=full name (root name not included) in TempPath
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

* Create dir and copy file from ENVARC: if possible
* Only used by LocateObject and UpNoti
* ENTRY: TempPath=name, d0=BPTR parent lock
* EXIT: d0=new file
CalcFullName:
	movem.l	d2-d6/a2-a4,-(sp)
	moveq	#0,d4			;d4=return code
	tst.b	WriteProtected(a5)
	bne	.fail
	tst.l	Copyfrom(a5)
	beq	.fail
	bsr	CreatePath
	beq	.fail
	move.l	d0,a1
	move.l	d0,a2
	move.b	#$40,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
	clr.b	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
	move.b	#$a0,myf_Type(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

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

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

* Debug output support subroutines and strings following

	IFD	DEBUG

* Output one character
RawHook	move.l	a6,-(sp)
	move.l	4.w,a6
	jsr	_LVORawPutChar(a6)
	move.l	(sp)+,a6
	rts

* Wait for CTRL-C signal
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, Locks=%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
txchng	dc.b	"  Changed mode, pos=%ld, size=%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=$%lx.",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
txexp	dc.b	"    Expanded path to %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, Locks=%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
txargs	dc.b	"Args: $%lx, $%lx, $%lx, $%lx.",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	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
txchng	dc.b	0;"  Changed mode, file=$%lx, pos=%ld, size=%ld.",10,0
txsize	dc.b	0;"  Changed size, file=$%lx, oldsize=%ld, newsize=%ld.",10,0
txseek	dc.b	0;"  Seeked, filepos=%ld.",10,0
txdel	dc.b	"  Deleted $%lx.",10,0

txlock	dc.b	0;"  Locked %s=$%lx mode %ld.",10,0
txulock	dc.b	0;"  Unlocked $%lx.",10,0
txexam	dc.b	0;"  Examined file=$%lx.",10,0
txexan	dc.b	0;"    Examined %s.",10,0
txexnx	dc.b	0;"  Examined next file=$%lx.",10,0
txfnd	dc.b	0;"    Found %s=$%lx type=$%lx.",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
txexp	dc.b	"    Expanded path to %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

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

* Alles hat ein Ende ...  ;-)

	END

