1 #include "asmsupport.h"
3 #include <exec/types.h>
4 #include <clib/macros.h> // MAX, MIN & ABS :-)
5 #include <devices/input.h>
6 #include <devices/inputevent.h>
7 #include <devices/timer.h>
8 #include <devices/trackdisk.h>
10 #include <dos/dosextens.h>
11 #include <dos/dostags.h>
12 #include <dos/exall.h>
13 #include <dos/filehandler.h>
14 #include <dos/notify.h>
15 #include <exec/errors.h>
16 #include <exec/interrupts.h>
18 #include <exec/lists.h>
19 #include <exec/memory.h>
20 #include <exec/nodes.h>
21 #include <exec/resident.h>
22 #include <libraries/iffparse.h>
23 #include <resources/filesysres.h>
24 #include <proto/dos.h>
25 #include <proto/exec.h>
26 #include <proto/intuition.h>
27 #include <proto/timer.h>
28 #include <proto/utility.h>
37 #include "adminspaces.h"
39 #include "btreenodes.h"
43 #include "transactions.h"
45 #include "adminspaces_protos.h"
46 #include "bitmap_protos.h"
47 #include "btreenodes_protos.h"
48 #include "cachebuffers_protos.h"
50 #include "locks_protos.h"
51 #include "nodes_protos.h"
52 #include "objects_protos.h"
55 #include "support_protos.h"
56 #include "transactions_protos.h"
57 #include "req_protos.h"
61 #include "cachedio_protos.h"
62 #include "deviceio_protos.h"
64 static LONG
fillgap(BLCK key
);
69 #define BITMAPFILL 0xFFFFFFFF /* should be 0xFFFFFFFF ! Careful.. admin containers are 32 blocks! */
73 #define BLCKFACCURACY (5) /* 2^5 = 32 */
75 #define ID_BUSY AROS_LONG2BE(MAKE_ID('B','U','S','Y'))
77 /* Our own usage of NotifyRequest private data */
78 #define nr_Next nr_Reserved[2]
79 #define nr_Prev nr_Reserved[3]
82 #define SFSM_ADD_VOLUMENODE (1)
83 #define SFSM_REMOVE_VOLUMENODE (2)
92 struct DefragmentStep
{
93 ULONG id
; // id of the step ("MOVE", "DONE" or 0)
94 ULONG length
; // length in longwords (can be 0)
95 ULONG data
[0]; // size of this array is determined by length.
99 /* global variables */
104 struct SFSBase
*globals
=NULL
;
109 static struct DosPacket
*getpacket(struct Process
*);
110 static struct DosPacket
*waitpacket(struct Process
*);
111 static void returnpacket(SIPTR
,LONG
);
112 static void sdlhtask(void);
114 /* Prototypes of cachebuffer related functions */
116 LONG
readcachebuffercheck(struct CacheBuffer
**,ULONG
,ULONG
);
117 void outputcachebuffer(struct CacheBuffer
*cb
);
119 /* Prototypes of node related functions */
121 LONG
deleteextents(ULONG key
);
122 static LONG
findextentbnode(ULONG key
,struct CacheBuffer
**returned_cb
,struct fsExtentBNode
**returned_bnode
);
123 static LONG
createextentbnode(ULONG key
,struct CacheBuffer
**returned_cb
,struct fsExtentBNode
**returned_bnode
);
125 /* Prototypes of debug functions */
127 ULONG
calcchecksum(void);
130 /* Misc prototypes */
132 void starttimeout(void);
133 LONG
flushcaches(void);
134 void invalidatecaches(void);
136 BOOL
freeupspace(void);
138 BOOL
checkchecksum(struct CacheBuffer
*);
139 void setchecksum(struct CacheBuffer
*);
141 void checknotifyforobject(struct CacheBuffer
*cb
,struct fsObject
*o
,UBYTE notifyparent
);
142 void checknotifyforpath(UBYTE
*path
,UBYTE notifyparent
);
143 void notify(struct NotifyRequest
*nr
);
144 UBYTE
*fullpath(struct CacheBuffer
*cbstart
,struct fsObject
*o
);
147 static void deinitdisk(void);
149 LONG
handlesimplepackets(struct DosPacket
*packet
);
150 static LONG
dumppackets(struct DosPacket
*packet
,LONG
);
152 static void dumppacket(void);
154 static void actioncurrentvolume(struct DosPacket
*);
155 static void actionsamelock(struct DosPacket
*);
156 static void actiondiskinfo(struct DosPacket
*);
157 static void fillinfodata(struct InfoData
*);
158 static void fillfib(struct FileInfoBlock
*,struct fsObject
*);
159 static void diskchangenotify(ULONG
class);
161 /* Prototypes of high-level filesystem functions */
163 LONG
setfilesize(struct ExtFileLock
*lock
,ULONG bytes
);
164 static LONG
seek(struct ExtFileLock
*lock
,ULONG offset
);
165 LONG
seektocurrent(struct ExtFileLock
*lock
);
166 LONG
seekextent(struct ExtFileLock
*lock
,ULONG offset
,struct CacheBuffer
**returned_cb
,struct fsExtentBNode
**returned_ebn
,ULONG
*returned_extentoffset
);
167 void seekforward(struct ExtFileLock
*lock
, UWORD ebn_blocks
, BLCK ebn_next
, ULONG bytestoseek
);
168 LONG
writetofile(struct ExtFileLock
*lock
, UBYTE
*buffer
, ULONG bytestowrite
);
170 static LONG
extendblocksinfile(struct ExtFileLock
*lock
,ULONG blocks
);
171 static LONG
addblocks(UWORD blocks
, BLCK newspace
, NODE objectnode
, BLCK
*io_lastextentbnode
);
172 LONG
deletefileslowly(struct CacheBuffer
*cbobject
, struct fsObject
*o
);
178 #define MAJOR_VERSION (1)
179 #define MINOR_VERSION (84)
182 const char ver_version
[]="\0$VER: " PROGRAMNAMEVER
" 1.84 (" ADATE
")\r\n";
184 static const char ver_version
[]={"\0$VER: " PROGRAMNAMEVER
" 1.84 " __AMIGADATE__
"\r\n"};
188 /* AROS builds in a 'struct Resident' automatically
191 /* ROMTag is useful for C:Version. */
192 #define res_Init NULL
194 const struct Resident resident
=
198 (APTR
)&resident
+ sizeof(struct Resident
),
212 extern const RESBASE
;
214 extern const _LinkerDB
;
215 extern const NEWDATAL
;
218 LONG
mainprogram(struct ExecBase
*);
225 LONG __saveds
trampoline(void)
227 struct ExecBase
*sBase
= (*((struct ExecBase
**)4));
229 return mainprogram(sBase
);
234 return(STACKSWAP(4096, trampoline
));
235 /* if(STACKSWAP()==0) {
236 return(ERROR_NO_FREE_STORE);
239 return(mainprogram()); */
243 void request2(UBYTE
*text
);
245 // #define STARTDEBUG
247 LONG
mainprogram(struct ExecBase
*SysBase
)
255 D(bug("[SFS] Filesystem main\n"));
257 globals
= AllocMem(sizeof(struct SFSBase
), MEMF_PUBLIC
| MEMF_CLEAR
);
259 globals
->sysBase
= SysBase
;
265 #define SysBase (globals->sysBase)
267 old_a4
=(APTR
)getreg(REG_A4
);
268 reslen
=((ULONG
)&RESLEN
-(ULONG
)old_a4
)+64;
270 newdata
=AllocMem(reslen
,MEMF_CLEAR
|MEMF_PUBLIC
);
272 CopyMem(old_a4
,newdata
,*(((ULONG
*)old_a4
)-2));
274 putreg(REG_A4
,(LONG
)newdata
);
277 if((DOSBase
=(struct DosLibrary
*)OpenLibrary("dos.library",37))!=0) {
278 D(bug("[SFS] DOSBase = %p\n", DOSBase
));
280 globals
->mytask
=(struct Process
*)FindTask(0);
281 D(bug("[SFS] mytask = %p\n", globals
->mytask
));
283 globals
->packet
=waitpacket(globals
->mytask
);
284 D(bug("[SFS] packet = %p\n", globals
->packet
));
286 globals
->devnode
=(struct DeviceNode
*)BADDR(globals
->packet
->dp_Arg3
);
287 globals
->devnode
->dn_Task
=&globals
->mytask
->pr_MsgPort
;
288 globals
->startupmsg
=BADDR(globals
->devnode
->dn_Startup
);
289 D(bug("[SFS] devnode = %p\n", globals
->devnode
));
290 D(bug("[SFS] startupmsg = %p\n", globals
->startupmsg
));
292 if(initcachebuffers()==0) {
294 if((IntuitionBase
=(APTR
)OpenLibrary("intuition.library",37))!=0) {
297 dreq("(1) Filesystem initializing...");
300 if((UtilityBase
=(APTR
)OpenLibrary("utility.library",37))!=0) {
302 /* Create a msgport and iorequest for opening timer.device */
304 if((globals
->msgportnotify
=CreateMsgPort())!=0) {
305 if((globals
->msgporttimer
=CreateMsgPort())!=0) {
306 if((globals
->msgportflushtimer
=CreateMsgPort())!=0) {
307 if((globals
->inactivitytimer_ioreq
=(struct timerequest
*)CreateIORequest(globals
->msgporttimer
, sizeof(struct timerequest
)))!=0) {
308 if((globals
->activitytimer_ioreq
=(struct timerequest
*)CreateIORequest(globals
->msgportflushtimer
, sizeof(struct timerequest
)))!=0) {
311 dreq("(2) Message ports and iorequests created");
314 if(OpenDevice("timer.device",UNIT_VBLANK
,&globals
->inactivitytimer_ioreq
->tr_node
,0)==0) {
315 if(OpenDevice("timer.device",UNIT_VBLANK
,&globals
->activitytimer_ioreq
->tr_node
,0)==0) {
317 globals
->dosenvec
=(struct DosEnvec
*)BADDR(globals
->startupmsg
->fssm_Environ
);
319 globals
->timerBase
=(struct Device
*)globals
->inactivitytimer_ioreq
->tr_node
.io_Device
;
321 /* Create a msgport and iorequest for opening the filesystem device */
323 initlist((struct List
*)&globals
->globalhandles
);
326 dreq("(3) Timer.device opened");
329 if(initcachedio(AROS_BSTR_ADDR(globals
->startupmsg
->fssm_Device
), globals
->startupmsg
->fssm_Unit
, globals
->startupmsg
->fssm_Flags
, globals
->dosenvec
)==0) {
331 dreq("(4) Cached IO layer started");
334 globals
->shifts_block32
=globals
->shifts_block
-BLCKFACCURACY
;
336 globals
->mask_block32
=(1<<globals
->shifts_block32
)-1;
337 globals
->blocks_inbitmap
=(globals
->bytes_block
-sizeof(struct fsBitmap
))<<3; /* must be a multiple of 32 !! */
338 globals
->blocks_bitmap
=(globals
->blocks_total
+globals
->blocks_inbitmap
-1)/globals
->blocks_inbitmap
;
339 globals
->blocks_admin
=32;
341 globals
->blocks_reserved_start
=MAX(globals
->dosenvec
->de_Reserved
,1);
342 globals
->blocks_reserved_end
=MAX(globals
->dosenvec
->de_PreAlloc
,1);
345 ULONG blocks512
, reserve
;
347 blocks512
=globals
->blocks_total
<<(globals
->shifts_block
-9);
348 reserve
=SQRT(blocks512
);
349 reserve
=(reserve
<<2) + reserve
;
351 if(reserve
> blocks512
/100) { // Do not use more than 1% of the disk.
352 reserve
= blocks512
/100;
355 if(reserve
< globals
->blocks_admin
) { // Use atleast 32 blocks, even if it is more than 1%.
356 reserve
= globals
->blocks_admin
;
357 if(reserve
> globals
->blocks_total
>>1) {
362 globals
->block_rovingblockptr
=globals
->blocks_reserved_start
+ globals
->blocks_admin
+ globals
->blocks_bitmap
+ reserve
;
364 _DEBUG(("RovingBlockPtr = %ld, reserve = %ld\n", globals
->block_rovingblockptr
, reserve
));
366 // block_rovingblockptr=0;
369 globals
->mask_debug
=0x00000000;
371 globals
->node_containers
=(globals
->bytes_block
-sizeof(struct fsNodeContainer
))/sizeof(BLCKn
);
373 addchangeint((struct Task
*)globals
->mytask
, 1<<globals
->mytask
->pr_MsgPort
.mp_SigBit
);
375 _DEBUG(("Initializing transactions\n"));
377 if(inittransactions()==0) {
380 dreq("(5) Transaction layer started");
383 if(addcachebuffers(globals
->dosenvec
->de_NumBuffers
)==0) {
386 dreq("(6) Filesystem started succesfully!");
389 /* return startup-packet, the handler runs now */
391 _DEBUG(("Filesystem started! Volumenode = %ld\n",globals
->volumenode
));
392 _DEBUG(("Mountlist entry says: Allocate %ld buffers of memtype 0x%08lx\n",globals
->dosenvec
->de_NumBuffers
,globals
->dosenvec
->de_BufMemType
));
394 // returnpacket(DOSTRUE,0); // Sep 19 1999: Moved down again.
396 _DEBUG(("CreateNewProc..."));
398 const struct TagItem tags
[]=
400 {NP_Entry
, (IPTR
)sdlhtask
},
401 {NP_Name
, (IPTR
)"SFS DosList handler"},
406 if(CreateNewProc(tags
)!=0) {
410 while((globals
->sdlhport
=FindPort("SFS DosList handler"))==0) {
414 if(isdiskpresent()!=FALSE
) {
416 dreq("There is a disk present.");
423 dreq("No disk inserted.");
426 globals
->disktype
=ID_NO_DISK_PRESENT
;
429 returnpacket(DOSTRUE
,0); // Jul 4 1999: Moved up...
432 dreq("(7) Informed DOS about the new partition!");
439 cleanuptransactions();
445 CloseDevice(&globals
->activitytimer_ioreq
->tr_node
);
447 CloseDevice(&globals
->inactivitytimer_ioreq
->tr_node
);
449 DeleteIORequest((struct IORequest
*)globals
->activitytimer_ioreq
);
451 DeleteIORequest((struct IORequest
*)globals
->inactivitytimer_ioreq
);
453 DeleteMsgPort(globals
->msgportflushtimer
);
455 DeleteMsgPort(globals
->msgporttimer
);
457 DeleteMsgPort(globals
->msgportnotify
);
459 CloseLibrary((struct Library
*)UtilityBase
);
463 dreq("Filesystem failed.. exiting.");
466 CloseLibrary((struct Library
*)IntuitionBase
);
470 _DEBUG(("Returning startup packet with DOSFALSE\n"));
472 returnpacket(DOSFALSE
,ERROR_NO_FREE_STORE
);
474 CloseLibrary((struct Library
*)DOSBase
);
477 FreeMem(globals
, sizeof(struct SFSBase
));
478 _DEBUG(("Exiting filesystem\n"));
480 return(ERROR_NO_FREE_STORE
);
484 void mainloop(void) {
486 struct MsgPort
*msgportpackets
;
489 msgportpackets
=&globals
->mytask
->pr_MsgPort
; /* get port of our process */
490 signalbits
=1<<msgportpackets
->mp_SigBit
;
491 signalbits
|=1<<globals
->msgporttimer
->mp_SigBit
;
492 signalbits
|=1<<globals
->msgportnotify
->mp_SigBit
;
493 signalbits
|=1<<globals
->msgportflushtimer
->mp_SigBit
;
496 dreq("Entering packet loop.");
504 while((msg
=GetMsg(globals
->msgportflushtimer
))!=0) {
505 _TDEBUG(("mainloop: activity timeout -> flushed transaction\n"));
507 globals
->activitytimeractive
=FALSE
;
510 while((msg
=GetMsg(globals
->msgporttimer
))!=0) {
511 if(globals
->timerreset
==TRUE
) {
512 /* There was another request during the timeout/2 period, so we extend the timeout a bit longer. */
513 globals
->pendingchanges
=FALSE
;
517 _TDEBUG(("mainloop: inactivity timeout -> flushed transaction\n"));
519 globals
->pendingchanges
=FALSE
;
523 while((msg
=GetMsg(globals
->msgportnotify
))!=0) {
524 FreeMem(msg
,sizeof(struct NotifyMessage
));
529 /* The disk was inserted or removed! */
531 _DEBUG(("mainloop: disk inserted or removed\n"));
533 if(isdiskpresent()==FALSE
) {
534 /* Disk was removed */
536 globals
->disktype
=ID_NO_DISK_PRESENT
; /* Must be put before deinitdisk() */
540 /* Disk was inserted */
546 if((msg
=GetMsg(msgportpackets
))!=0) {
549 // diskstate=writeprotection(); /* Don't do this too often!! It takes LOADS of time for scsi.device. */
552 #ifdef CHECKCODE_SLOW
554 struct CacheBuffer
*cb
;
556 cb
=(struct CacheBuffer
*)cblrulist
.mlh_Head
;
558 while(cb
->node
.mln_Succ
!=0) {
560 request(PROGRAMNAME
" request","%s\n"\
561 "mainloop: There was a locked CacheBuffer (lockcount = %ld, block = %ld, type = 0x%08lx)!\n"\
562 "Nothing bad will happen, but let the author know.\n",
563 "Ok",AROS_BSTR_ADDR(devnode
->dn_Name
), cb
->locked
, cb
->blckno
, *((ULONG
*)cb
->data
));
566 cb
->locked
=0; /* Nothing remains locked */
569 cb
=(struct CacheBuffer
*)(cb
->node
.mln_Succ
);
575 globals
->packet
=(struct DosPacket
*)msg
->mn_Node
.ln_Name
;
578 dreq("Received packet 0x%08lx, %ld.",globals
->packet
,globals
->packet
->dp_Type
);
581 switch(globals
->packet
->dp_Type
) {
584 struct TagItem
*taglist
=(struct TagItem
*)globals
->packet
->dp_Arg1
;
587 while((tag
=NextTagItem(&taglist
))!=NULL
) {
588 LONG data
=tag
->ti_Data
;
590 switch(tag
->ti_Tag
) {
591 case ASS_MAX_NAME_LENGTH
:
592 if(data
>= 30 && data
<= 100) {
593 globals
->max_name_length
=data
;
596 case ASS_ACTIVITY_FLUSH_TIMEOUT
:
597 if(data
>= 5 && data
<= 120) {
598 globals
->activity_timeout
=data
;
601 case ASS_INACTIVITY_FLUSH_TIMEOUT
:
602 if(data
>= 1 && data
<= 5) {
603 globals
->inactivity_timeout
=data
;
609 returnpacket(DOSTRUE
,0);
612 case ACTION_SFS_QUERY
:
614 struct TagItem
*taglist
=(struct TagItem
*)globals
->packet
->dp_Arg1
;
617 while((tag
=NextTagItem(&taglist
)))
621 case ASQ_START_BYTEH
:
622 tag
->ti_Data
= globals
->byte_low
>> 32;
625 case ASQ_START_BYTEL
:
627 * Explicitly cast to ULONG here because on 64 bits
628 * ti_Data is 64-bit wide, and this can confuse programs.
630 tag
->ti_Data
= (ULONG
)globals
->byte_low
;
634 tag
->ti_Data
= globals
->byte_high
>> 32;
638 tag
->ti_Data
= (ULONG
)globals
->byte_high
;
642 tag
->ti_Data
=deviceapiused();
645 tag
->ti_Data
=globals
->bytes_block
;
647 case ASQ_TOTAL_BLOCKS
:
648 tag
->ti_Data
=globals
->blocks_total
;
651 tag
->ti_Data
=globals
->block_root
;
653 case ASQ_ROOTBLOCK_OBJECTNODES
:
654 tag
->ti_Data
=globals
->block_objectnoderoot
;
656 case ASQ_ROOTBLOCK_EXTENTS
:
657 tag
->ti_Data
=globals
->block_extentbnoderoot
;
659 case ASQ_FIRST_BITMAP_BLOCK
:
660 tag
->ti_Data
=globals
->block_bitmapbase
;
662 case ASQ_FIRST_ADMINSPACE
:
663 tag
->ti_Data
=globals
->block_adminspace
;
665 case ASQ_CACHE_LINES
:
666 tag
->ti_Data
=queryiocache_lines();
668 case ASQ_CACHE_READAHEADSIZE
:
669 tag
->ti_Data
=queryiocache_readaheadsize();
672 tag
->ti_Data
=queryiocache_copyback();
674 case ASQ_CACHE_BUFFERS
:
675 tag
->ti_Data
=globals
->totalbuffers
;
677 case ASQ_CACHE_ACCESSES
:
678 tag
->ti_Data
=globals
->statistics
.cache_accesses
;
680 case ASQ_CACHE_MISSES
:
681 tag
->ti_Data
=globals
->statistics
.cache_misses
;
683 case ASQ_OPERATIONS_DECODED
:
684 tag
->ti_Data
=globals
->statistics
.cache_operationdecode
;
686 case ASQ_EMPTY_OPERATIONS_DECODED
:
687 tag
->ti_Data
=globals
->statistics
.cache_emptyoperationdecode
;
689 case ASQ_IS_CASESENSITIVE
:
690 tag
->ti_Data
=globals
->is_casesensitive
;
692 case ASQ_HAS_RECYCLED
:
693 tag
->ti_Data
=globals
->has_recycled
;
696 tag
->ti_Data
=MAJOR_VERSION
* 65536 + MINOR_VERSION
;
698 case ASQ_MAX_NAME_LENGTH
:
699 tag
->ti_Data
=globals
->max_name_length
;
701 case ASQ_ACTIVITY_FLUSH_TIMEOUT
:
702 tag
->ti_Data
=globals
->activity_timeout
;
704 case ASQ_INACTIVITY_FLUSH_TIMEOUT
:
705 tag
->ti_Data
=globals
->inactivity_timeout
;
710 returnpacket(DOSTRUE
,0);
713 case ACTION_SET_DEBUG
:
714 _DEBUG(("New debug level set to 0x%08lx!\n",globals
->packet
->dp_Arg1
));
716 globals
->mask_debug
=globals
->packet
->dp_Arg1
;
718 returnpacket(DOSTRUE
,0);
721 case ACTION_SET_CACHE
:
722 _DEBUG(("ACTION_SET_CACHE\n"));
726 if((errorcode
=setiocache(globals
->packet
->dp_Arg1
, globals
->packet
->dp_Arg2
, globals
->packet
->dp_Arg3
& 1))!=0) {
727 returnpacket(DOSFALSE
, errorcode
);
730 returnpacket(DOSTRUE
, 0);
735 case ACTION_SFS_FORMAT
:
737 _DEBUG(("ACTION_FORMAT\n"));
740 struct CacheBuffer
*cb
;
746 UBYTE
*recycledname
=".recycled";
747 BYTE casesensitive
=FALSE
;
748 BYTE norecycled
=FALSE
;
749 BYTE showrecycled
=FALSE
;
750 currentdate
=getdate();
752 if(globals
->packet
->dp_Type
==ACTION_SFS_FORMAT
) {
753 struct TagItem
*taglist
=(struct TagItem
*)globals
->packet
->dp_Arg1
;
756 while((tag
=NextTagItem(&taglist
))) {
757 switch(tag
->ti_Tag
) {
759 name
=(UBYTE
*)tag
->ti_Data
;
761 case ASF_RECYCLEDNAME
:
762 recycledname
=(UBYTE
*)tag
->ti_Data
;
764 case ASF_CASESENSITIVE
:
765 casesensitive
=tag
->ti_Data
;
768 norecycled
=tag
->ti_Data
;
770 case ASF_SHOWRECYCLED
:
771 showrecycled
=tag
->ti_Data
;
777 copybstrasstr((BSTR
)globals
->packet
->dp_Arg1
, globals
->string
, 30);
778 name
=globals
->string
;
781 /* Global block numbers */
783 globals
->block_adminspace
=globals
->blocks_reserved_start
;
784 globals
->block_root
=globals
->blocks_reserved_start
+1;
785 globals
->block_extentbnoderoot
=globals
->block_root
+3;
786 globals
->block_bitmapbase
=globals
->block_adminspace
+globals
->blocks_admin
;
787 globals
->block_objectnoderoot
=globals
->block_root
+4;
789 /* Temporary block numbers */
791 block_recycled
=globals
->block_root
+5;
795 if(isvalidcomponentname(name
)==FALSE
|| isvalidcomponentname(recycledname
)==FALSE
) {
796 errorcode
=ERROR_INVALID_COMPONENT_NAME
;
800 struct fsAdminSpaceContainer
*ac
=cb
->data
;
802 _DEBUG(("ACTION_FORMAT: Creating AdminSpace container block\n"));
804 /* Create AdminSpaceContainer block */
806 cb
->blckno
=globals
->block_adminspace
;
807 clearcachebuffer(cb
);
809 ac
->bheader
.id
=ADMINSPACECONTAINER_ID
;
810 ac
->bheader
.be_ownblock
=L2BE(globals
->block_adminspace
);
811 ac
->bits
=globals
->blocks_admin
;
812 ac
->adminspace
[0].be_space
=L2BE(globals
->block_adminspace
);
814 if(norecycled
==FALSE
) {
815 /* NOT HASHED RECYCLED
816 ac->adminspace[0].be_bits=L2BE(0xFF000000); // admin + root + hashtable + restore + 2 * nodecontainers + recycled + hash
818 ac
->adminspace
[0].be_bits
=L2BE(0xFE000000); /* admin + root + hashtable + restore + 2 * nodecontainers + recycled */
821 ac
->adminspace
[0].be_bits
=L2BE(0xFC000000); /* admin + root + hashtable + restore + 2 * nodecontainers */
825 errorcode
=writecachebuffer(cb
);
829 struct fsObjectContainer
*oc
=cb
->data
;
830 struct fsRootInfo
*ri
=(struct fsRootInfo
*)((UBYTE
*)cb
->data
+globals
->bytes_block
-sizeof(struct fsRootInfo
));
832 _DEBUG(("ACTION_FORMAT: Creating Root block\n"));
834 /* Create Root block */
836 cb
->blckno
=globals
->block_root
;
837 clearcachebuffer(cb
);
839 oc
->bheader
.id
=OBJECTCONTAINER_ID
;
840 oc
->bheader
.be_ownblock
=L2BE(globals
->block_root
);
841 oc
->object
[0].be_protection
=L2BE(FIBF_READ
|FIBF_WRITE
|FIBF_EXECUTE
|FIBF_DELETE
);
842 oc
->object
[0].be_datemodified
=L2BE(currentdate
);
843 oc
->object
[0].bits
=OTYPE_DIR
;
844 oc
->object
[0].be_objectnode
=L2BE(ROOTNODE
);
846 oc
->object
[0].object
.dir
.be_hashtable
=L2BE(globals
->block_root
+1);
848 if(norecycled
==FALSE
) {
849 oc
->object
[0].object
.dir
.be_firstdirblock
=L2BE(block_recycled
);
852 copystr(name
, oc
->object
[0].name
, 30);
854 ri
->be_freeblocks
=L2BE(globals
->blocks_total
-globals
->blocks_admin
-globals
->blocks_reserved_start
-globals
->blocks_reserved_end
-globals
->blocks_bitmap
);
855 ri
->be_datecreated
=oc
->object
[0].be_datemodified
; // BE-BE copy
858 errorcode
=writecachebuffer(cb
);
862 struct fsHashTable
*ht
=cb
->data
;
864 _DEBUG(("ACTION_FORMAT: Creating Root's HashTable block\n"));
866 /* Create Root's HashTable block */
868 cb
->blckno
=globals
->block_root
+1;
869 clearcachebuffer(cb
);
871 ht
->bheader
.id
=HASHTABLE_ID
;
872 ht
->bheader
.be_ownblock
=L2BE(globals
->block_root
+1);
873 ht
->be_parent
=L2BE(ROOTNODE
);
875 if(norecycled
==FALSE
) {
876 ht
->be_hashentry
[HASHCHAIN(hash(".recycled", casesensitive
))]=L2BE(RECYCLEDNODE
);
880 errorcode
=writecachebuffer(cb
);
884 struct fsBlockHeader
*bh
=cb
->data
;
886 _DEBUG(("ACTION_FORMAT: Creating Transaction block\n"));
888 /* Create empty block as a placeholder for the TransactionFailure block. */
890 cb
->blckno
=globals
->block_root
+2;
891 clearcachebuffer(cb
);
893 bh
->id
=TRANSACTIONOK_ID
;
894 bh
->be_ownblock
=L2BE(globals
->block_root
+2);
897 errorcode
=writecachebuffer(cb
);
901 struct fsBNodeContainer
*bnc
=cb
->data
;
902 struct BTreeContainer
*btc
=&bnc
->btc
;
904 _DEBUG(("ACTION_FORMAT: Creating ExtentNode root block\n"));
906 /* Create NodeContainer block for ExtentNodes */
908 cb
->blckno
=globals
->block_extentbnoderoot
;
909 clearcachebuffer(cb
);
911 bnc
->bheader
.id
=BNODECONTAINER_ID
;
912 bnc
->bheader
.be_ownblock
=L2BE(globals
->block_extentbnoderoot
);
916 btc
->nodesize
=sizeof(struct fsExtentBNode
);
919 errorcode
=writecachebuffer(cb
);
923 struct fsNodeContainer
*nc
=cb
->data
;
924 struct fsObjectNode
*on
;
926 _DEBUG(("ACTION_FORMAT: Creating ObjectNode root block\n"));
928 /* Create NodeContainer block for ObjectNodes */
930 cb
->blckno
=globals
->block_objectnoderoot
;
931 clearcachebuffer(cb
);
933 nc
->bheader
.id
=NODECONTAINER_ID
;
934 nc
->bheader
.be_ownblock
=L2BE(globals
->block_objectnoderoot
);
936 nc
->be_nodenumber
=L2BE(1); /* objectnode 0 is reserved :-) */
937 nc
->be_nodes
=L2BE(1);
939 on
=(struct fsObjectNode
*)nc
->be_node
;
940 on
->node
.be_data
=L2BE(globals
->block_root
);
943 if(norecycled
==FALSE
) {
944 on
->node
.be_data
=L2BE(block_recycled
);
945 on
->be_hash16
=W2BE(hash(".recycled", casesensitive
));
948 on
->node
.be_data
=-1; // reserved 2
952 on
->node
.be_data
=-1; // reserved 3
955 on
->node
.be_data
=-1; // reserved 4
958 on
->node
.be_data
=-1; // reserved 5
961 on
->node
.be_data
=-1; // reserved 6
964 errorcode
=writecachebuffer(cb
);
967 if(errorcode
==0 && norecycled
==FALSE
) {
968 struct fsObjectContainer
*oc
=cb
->data
;
970 _DEBUG(("ACTION_FORMAT: Creating Root ObjectContainer block\n"));
972 cb
->blckno
=block_recycled
;
973 clearcachebuffer(cb
);
975 oc
->bheader
.id
=OBJECTCONTAINER_ID
;
976 oc
->bheader
.be_ownblock
=L2BE(block_recycled
);
977 oc
->be_parent
=L2BE(ROOTNODE
);
978 oc
->object
[0].be_protection
=L2BE(FIBF_READ
|FIBF_WRITE
);
979 oc
->object
[0].be_datemodified
=L2BE(currentdate
);
980 oc
->object
[0].bits
=OTYPE_DIR
|OTYPE_UNDELETABLE
|OTYPE_QUICKDIR
;
981 if(showrecycled
==FALSE
) {
982 oc
->object
[0].bits
|=OTYPE_HIDDEN
;
985 oc
->object
[0].be_objectnode
=L2BE(RECYCLEDNODE
);
987 /* NOT HASHED RECYCLED
988 oc->object[0].object.dir.hashtable=block_recycled+1;
990 oc
->object
[0].object
.dir
.be_hashtable
=0;
992 copystr(".recycled",oc
->object
[0].name
,30);
995 errorcode
=writecachebuffer(cb
);
998 /* NOT HASHED RECYCLED
999 if(errorcode==0 && norecycled==FALSE) {
1000 struct fsHashTable *ht=cb->data;
1002 _DEBUG(("ACTION_FORMAT: Creating Recycled's HashTable block\n"));
1004 cb->blckno=block_recycled+1;
1005 clearcachebuffer(cb);
1007 ht->bheader.id=HASHTABLE_ID;
1008 ht->bheader.ownblock=block_recycled+1;
1009 ht->parent=RECYCLEDNODE;
1012 errorcode=writecachebuffer(cb);
1017 struct fsBitmap
*bm
;
1019 ULONG block
=globals
->block_bitmapbase
;
1020 LONG startfree
=globals
->blocks_admin
+globals
->blocks_bitmap
+globals
->blocks_reserved_start
;
1023 _DEBUG(("ACTION_FORMAT: Creating the Bitmap blocks\n"));
1025 /* Create Bitmap blocks */
1027 sizefree
=globals
->blocks_total
-startfree
-globals
->blocks_reserved_end
;
1029 cnt
=globals
->blocks_bitmap
;
1030 while(cnt
-->0 && errorcode
==0) {
1031 clearcachebuffer(cb
);
1034 bm
->bheader
.id
=BITMAP_ID
;
1035 bm
->bheader
.be_ownblock
=L2BE(block
);
1037 for(cnt2
=0; cnt2
<(globals
->blocks_inbitmap
>>5); cnt2
++) {
1041 bm
->bitmap
[cnt2
]=AROS_LONG2BE((1<<(-startfree
))-1);
1042 sizefree
+=startfree
;
1045 else if(sizefree
>0) {
1048 bm
->bitmap
[cnt2
]=AROS_LONG2BE(~((1<<(-sizefree
))-1));
1051 bm
->bitmap
[cnt2
]=BITMAPFILL
;
1062 errorcode
=writecachebuffer(cb
);
1067 struct fsRootBlock
*rb
;
1069 _DEBUG(("ACTION_FORMAT: Creating the Root blocks\n"));
1071 /* Create Root blocks */
1074 clearcachebuffer(cb
);
1077 rb
->bheader
.id
=L2BE(DOSTYPE_ID
);
1078 rb
->bheader
.be_ownblock
=0;
1080 rb
->be_version
=W2BE(STRUCTURE_VERSION
);
1081 rb
->be_sequencenumber
=0;
1083 rb
->be_datecreated
=L2BE(currentdate
);
1085 rb
->be_firstbyteh
= L2BE(globals
->byte_low
>> 32);
1086 rb
->be_firstbyte
= L2BE(globals
->byte_low
);
1087 rb
->be_lastbyteh
= L2BE(globals
->byte_high
>> 32);
1088 rb
->be_lastbyte
= L2BE(globals
->byte_high
);
1090 rb
->be_totalblocks
=L2BE(globals
->blocks_total
);
1091 rb
->be_blocksize
=L2BE(globals
->bytes_block
);
1093 rb
->be_bitmapbase
=L2BE(globals
->block_bitmapbase
);
1094 rb
->be_adminspacecontainer
=L2BE(globals
->block_adminspace
);
1095 rb
->be_rootobjectcontainer
=L2BE(globals
->block_root
);
1096 rb
->be_extentbnoderoot
=L2BE(globals
->block_extentbnoderoot
);
1097 rb
->be_objectnoderoot
=L2BE(globals
->block_objectnoderoot
);
1099 if(casesensitive
!=FALSE
) {
1100 rb
->bits
|=ROOTBITS_CASESENSITIVE
;
1102 if(norecycled
==FALSE
) {
1103 rb
->bits
|=ROOTBITS_RECYCLED
;
1107 if((errorcode
=writecachebuffer(cb
))==0) {
1108 cb
->blckno
=globals
->blocks_total
-1;
1110 _DEBUG(("ACTION_FORMAT: Creating the 2nd Root block\n"));
1112 rb
->bheader
.be_ownblock
=L2BE(globals
->blocks_total
-1);
1115 errorcode
=writecachebuffer(cb
);
1124 _DEBUG(("ACTION_FORMAT: Exiting with errorcode %ld\n",errorcode
));
1126 returnpacket(DOSFALSE
, errorcode
);
1129 returnpacket(DOSTRUE
, 0);
1134 case ACTION_INHIBIT
:
1135 _DEBUG(("ACTION_INHIBIT(%ld)\n",globals
->packet
->dp_Arg1
));
1137 /* This function nests. Each call to inhibit the disk should be matched
1138 with one to uninhibit the disk. */
1140 if(globals
->packet
->dp_Arg1
!=DOSFALSE
) {
1142 dreq("Disk inhibited (nesting = %ld).", globals
->inhibitnestcounter
);
1145 if(globals
->inhibitnestcounter
++==0) { // Inhibited for the first time?
1146 globals
->disktype
=ID_BUSY
; /* Must be put before deinitdisk() Feb 27 1999: Maybe not needed anymore */
1150 returnpacket(DOSTRUE
,0);
1152 else if(globals
->inhibitnestcounter
>0 && --globals
->inhibitnestcounter
==0) {
1154 returnpacket(DOSTRUE
, 0); /* Workbench keeps doslist locked, and doesn't send any packets
1155 during that time to this handler. As initdisk() needs to lock
1156 the doslist we MUST return the packet before calling initdisk() */
1160 /* Workbench revokes ACTION_INHIBIT without ever actually having
1161 inhibited the volume. We'll just return the packet and ignore
1164 returnpacket(DOSTRUE
,0);
1167 case ACTION_SERIALIZE_DISK
:
1168 _DEBUG(("ACTION_SERIALIZE_DISK\n"));
1171 struct CacheBuffer
*cb
;
1174 if((errorcode
=readcachebuffercheck(&cb
,globals
->block_root
,OBJECTCONTAINER_ID
))==0) {
1175 struct fsObjectContainer
*oc
=cb
->data
;
1176 struct fsRootInfo
*ri
=(struct fsRootInfo
*)((UBYTE
*)cb
->data
+globals
->bytes_block
-sizeof(struct fsRootInfo
));
1178 oc
->object
[0].be_datemodified
=L2BE(getdate());
1179 ri
->be_datecreated
=oc
->object
[0].be_datemodified
; // BE-BE copy
1182 errorcode
=writecachebuffer(cb
);
1186 returnpacket(DOSFALSE
,errorcode
);
1189 returnpacket(DOSTRUE
,0);
1195 if(handlesimplepackets(globals
->packet
)==0) {
1197 if(globals
->disktype
== DOSTYPE_ID
) {
1198 switch(globals
->packet
->dp_Type
) {
1199 case ACTION_MAKE_LINK
:
1200 _DEBUG(("ACTION_MAKE_LINK\n"));
1203 if(globals
->packet
->dp_Arg4
==LINK_HARD
) {
1204 returnpacket(DOSFALSE
,ERROR_ACTION_NOT_KNOWN
);
1206 /* else if(packet->dp_Arg4!=LINK_SOFT) {
1207 returnpacket(DOSFALSE,ERROR_BAD_NUMBER);
1208 } */ /* Check removed because DOS apparantely defines non-zero as being a Soft link! */
1210 struct ExtFileLock
*lock
;
1213 lock
=(struct ExtFileLock
*)BADDR(globals
->packet
->dp_Arg1
);
1214 copybstrasstr((BSTR
)globals
->packet
->dp_Arg2
,globals
->string
,258);
1216 _DEBUG(("ACTION_MAKE_LINK: Name = '%s', LinkPath = '%s'\n",globals
->string
,(UBYTE
*)globals
->packet
->dp_Arg3
));
1218 if((errorcode
=findcreate(&lock
,globals
->string
,globals
->packet
->dp_Type
,(UBYTE
*)globals
->packet
->dp_Arg3
))!=0) {
1219 returnpacket(DOSFALSE
,errorcode
);
1223 returnpacket(DOSTRUE
,0);
1229 case ACTION_READ_LINK
:
1230 _DEBUG(("ACTION_READ_LINK\n"));
1233 struct CacheBuffer
*cb
;
1235 struct ExtFileLock
*lock
;
1236 UBYTE
*dest
=(UBYTE
*)globals
->packet
->dp_Arg3
;
1240 lock
=(struct ExtFileLock
*)BADDR(globals
->packet
->dp_Arg1
);
1243 objectnode
=ROOTNODE
;
1246 objectnode
=lock
->objectnode
;
1249 if((errorcode
=readobject(objectnode
, &cb
, &o
))==0) {
1250 UBYTE
*path
=(UBYTE
*)globals
->packet
->dp_Arg2
, *prefix
=path
;
1252 _DEBUG(("ACTION_READ_LINK: path = '%s', errorcode = %ld\n",path
,errorcode
));
1254 errorcode
=locateobject2(&path
, &cb
, &o
);
1256 if(errorcode
!=ERROR_IS_SOFT_LINK
) {
1257 errorcode
=ERROR_OBJECT_NOT_FOUND
;
1260 struct CacheBuffer
*cb2
;
1263 /* Move on to remainder of path after the link */
1272 _DEBUG(("ACTION_READ_LINK: path = '%s'\n",path
));
1274 if((errorcode
=readcachebuffercheck(&cb2
, BE2L(o
->object
.file
.be_data
), SOFTLINK_ID
))==0) {
1275 struct fsSoftLink
*sl
=cb2
->data
;
1276 LONG length
=globals
->packet
->dp_Arg4
;
1277 UBYTE
*src
=sl
->string
, ch
;
1278 UBYTE
*s
=globals
->string
;
1280 while((*s
++=*path
++)!=0) { // Work-around for bug in ixemul, which sometimes provides the same pointer for dp_Arg2 (path) and dp_Arg3 (soft-link buffer)
1285 _DEBUG(("ACTION_READ_LINK: length = %ld, sl->string = '%s', path = '%s'\n", length
, sl
->string
, s
));
1287 /* cb is no longer valid at this point. */
1289 /* Check if link target is an absolute path */
1291 while((ch
=*src
++)!='\0') {
1297 /* If target is a relative path, put path preceding
1298 link into buffer so that result is relative to
1302 while(prefix
!=p
&& length
-->0) {
1307 /* Copy link target to buffer */
1309 while(length
-->0 && (*dest
++=*src
++)!=0) {
1314 /* Ensure we don't insert an extraneous slash */
1316 if(length
!=globals
->packet
->dp_Arg4
&& *(dest
-1)=='/') {
1320 if(*(dest
-1)==':' && *s
=='/') {
1324 /* Append remainder of original path */
1326 while(length
-->0 && (*dest
++=*s
++)!=0) {
1330 errorcode
=ERROR_LINE_TOO_LONG
;
1337 if(errorcode
==ERROR_LINE_TOO_LONG
) {
1338 returnpacket(-2, errorcode
);
1341 returnpacket(-1, errorcode
);
1345 returnpacket((LONG
)((SIPTR
)dest
- globals
->packet
->dp_Arg3
- 1),
1350 case ACTION_CREATE_DIR
:
1351 _DEBUG(("ACTION_CREATE_DIR\n"));
1354 struct ExtFileLock
*lock
;
1357 lock
=(struct ExtFileLock
*)BADDR(globals
->packet
->dp_Arg1
);
1358 copybstrasstr((BSTR
)globals
->packet
->dp_Arg2
,globals
->string
,258);
1360 if((errorcode
=findcreate(&lock
,globals
->string
,globals
->packet
->dp_Type
,0))!=0) {
1361 returnpacket(0,errorcode
);
1364 returnpacket((SIPTR
)TOBADDR(lock
),0);
1369 case ACTION_FINDUPDATE
:
1370 case ACTION_FINDINPUT
:
1371 case ACTION_FINDOUTPUT
:
1372 case ACTION_FH_FROM_LOCK
:
1373 _XDEBUG((DEBUG_OBJECTS
, "ACTION_FIND#? or ACTION_FH_FROM_LOCK\n"));
1376 struct ExtFileLock
*lock
;
1377 struct FileHandle
*fh
;
1380 fh
=(struct FileHandle
*)BADDR(globals
->packet
->dp_Arg1
);
1381 lock
=(struct ExtFileLock
*)BADDR(globals
->packet
->dp_Arg2
);
1383 if(globals
->packet
->dp_Type
!=ACTION_FH_FROM_LOCK
) {
1384 copybstrasstr((BSTR
)globals
->packet
->dp_Arg3
,globals
->string
,258);
1385 _DEBUG(("OPEN FILE: %s (mode = %ld)\n", globals
->string
, globals
->packet
->dp_Type
));
1386 errorcode
=findcreate(&lock
,globals
->string
,globals
->packet
->dp_Type
,0);
1390 if((errorcode
=createglobalhandle(lock
))==0) {
1391 fh
->fh_Arg1
=(IPTR
)lock
;
1393 else if(globals
->packet
->dp_Type
!=ACTION_FH_FROM_LOCK
) {
1399 returnpacket(DOSFALSE
,errorcode
);
1402 if(globals
->packet
->dp_Type
==ACTION_FINDOUTPUT
&& globals
->has_recycled
!=FALSE
) {
1405 if((errorcode
=getrecycledinfo(&files
, &blocks
))==0) {
1407 cleanupdeletedfiles();
1412 returnpacket(DOSTRUE
,0);
1418 _XDEBUG((DEBUG_OBJECTS
, "ACTION_END\n"));
1420 /* ACTION_FREE_LOCK's code is similair */
1423 struct ExtFileLock
*lock
=(struct ExtFileLock
*)globals
->packet
->dp_Arg1
;
1426 /* If a file has been modified by the use of ACTION_SET_FILE_SIZE or
1427 ACTION_WRITE, or ACTION_FINDOUTPUT or ACTION_FINDUPDATE (only when
1428 creating a new file) were used to create the file then we must
1429 also update the datestamp of the file. We also must send out a
1430 notification. Finally we also need to clear the A bit.
1432 For this purpose a special flag in the lock tells us
1433 whether or not any of the above actions has occured. */
1435 if((lock
->bits
& EFL_MODIFIED
) != 0) {
1436 struct CacheBuffer
*cb
;
1441 if(lock
->lastextendedblock
!=0) {
1442 globals
->block_rovingblockptr
=lock
->lastextendedblock
;
1443 if(globals
->block_rovingblockptr
>=globals
->blocks_total
) {
1444 globals
->block_rovingblockptr
=0;
1448 if((errorcode
=readobject(lock
->objectnode
, &cb
, &o
))==0) {
1451 errorcode
=bumpobject(cb
, o
);
1452 checknotifyforobject(cb
, o
, TRUE
);
1458 deletetransaction();
1462 /* Ignore any errorcodes -- not really interesting when closing a file... */
1465 if((errorcode
=freelock(lock
))!=0) {
1466 returnpacket(DOSFALSE
,errorcode
);
1469 returnpacket(DOSTRUE
,0);
1473 case ACTION_DELETE_OBJECT
:
1477 copybstrasstr((BSTR
)globals
->packet
->dp_Arg2
,globals
->string
,258);
1479 _DEBUG(("ACTION_DELETE_OBJECT(0x%08lx,'%s')\n",BADDR(globals
->packet
->dp_Arg1
),globals
->string
));
1484 if((errorcode
=deleteobject(BADDR(globals
->packet
->dp_Arg1
), validatepath(globals
->string
), TRUE
))==0) {
1488 deletetransaction();
1490 } while(errorcode
==ERROR_DISK_FULL
&& freeupspace()!=FALSE
);
1493 returnpacket(DOSFALSE
,errorcode
);
1498 if((errorcode
=getrecycledinfo(&files
, &blocks
))==0) {
1500 cleanupdeletedfiles();
1504 returnpacket(DOSTRUE
,0);
1508 case ACTION_RENAME_DISK
:
1509 _DEBUG(("ACTION_RENAME_DISK\n"));
1512 struct CacheBuffer
*cb
;
1515 if((errorcode
=readcachebuffercheck(&cb
,globals
->block_root
,OBJECTCONTAINER_ID
))==0) {
1516 if(AttemptLockDosList(LDF_WRITE
|LDF_VOLUMES
)!=0) {
1517 struct fsObjectContainer
*oc
=cb
->data
;
1520 #ifndef USE_FAST_BSTR
1524 /* Succesfully locked the doslist */
1528 preparecachebuffer(cb
);
1531 s
=BADDR(globals
->packet
->dp_Arg1
);
1532 d
=oc
->object
[0].name
;
1533 d
[copybstrasstr((BSTR
)globals
->packet
->dp_Arg1
, d
, 30)+1] = 0;
1545 *d
=0; /* Zero for comment */
1547 if((errorcode
=storecachebuffer(cb
))==0 && globals
->volumenode
!=0) {
1548 s
=BADDR(globals
->packet
->dp_Arg1
);
1549 d
=BADDR(globals
->volumenode
->dl_Name
);
1550 #ifdef USE_FAST_BSTR
1567 UnLockDosList(LDF_WRITE
|LDF_VOLUMES
);
1573 deletetransaction();
1577 /* Doslist locking attempt was unsuccesful. Send this message back to our
1578 port to try it again later. */
1580 PutMsg(msgportpackets
,msg
);
1586 returnpacket(DOSTRUE
,0);
1589 returnpacket(DOSFALSE
,errorcode
);
1593 case ACTION_RENAME_OBJECT
:
1594 _DEBUG(("ACTION_RENAME_OBJECT\n"));
1600 struct CacheBuffer
*cb
;
1602 struct ExtFileLock
*lock
;
1606 lock
=BADDR(globals
->packet
->dp_Arg1
);
1607 copybstrasstr((BSTR
)globals
->packet
->dp_Arg2
,globals
->string
,258);
1609 if((errorcode
=locateobjectfromlock(lock
,validatepath(globals
->string
),&cb
,&o
))==0) {
1610 copybstrasstr((BSTR
)globals
->packet
->dp_Arg4
,globals
->string
,258);
1612 settemporarylock(BE2L(o
->be_objectnode
));
1614 newname
=validatepath(globals
->string
);
1615 s
=FilePart(newname
);
1619 if((errorcode
=renameobject(cb
,o
,BADDR(globals
->packet
->dp_Arg3
),newname
))==0) {
1623 deletetransaction();
1627 errorcode
=ERROR_INVALID_COMPONENT_NAME
;
1630 } while(errorcode
==ERROR_DISK_FULL
&& freeupspace()!=FALSE
);
1632 cleartemporarylock();
1635 returnpacket(DOSFALSE
,errorcode
);
1638 returnpacket(DOSTRUE
,0);
1642 case ACTION_SET_COMMENT
:
1643 _DEBUG(("ACTION_SET_COMMENT\n"));
1648 copybstrasstr((BSTR
)globals
->packet
->dp_Arg3
,globals
->string
,258);
1649 copybstrasstr((BSTR
)globals
->packet
->dp_Arg4
,globals
->string2
,258);
1652 if((errorcode
=setcomment(BADDR(globals
->packet
->dp_Arg2
),validatepath(globals
->string
),globals
->string2
))!=0) {
1653 deletetransaction();
1658 } while(errorcode
==ERROR_DISK_FULL
&& freeupspace()!=FALSE
);
1661 returnpacket(DOSFALSE
,errorcode
);
1664 returnpacket(DOSTRUE
,0);
1668 case ACTION_SET_DATE
:
1669 case ACTION_SET_PROTECT
:
1670 case ACTION_SET_OWNER
:
1671 case ACTION_SFS_SET_OBJECTBITS
:
1672 _XDEBUG((DEBUG_OBJECTS
, "ACTION_SET_DATE or ACTION_SET_PROTECT or ACTION_SET_OWNER\n"));
1678 struct CacheBuffer
*cb
;
1680 struct ExtFileLock
*lock
;
1682 lock
=BADDR(globals
->packet
->dp_Arg2
);
1683 copybstrasstr((BSTR
)globals
->packet
->dp_Arg3
,globals
->string
,258);
1685 if((errorcode
=locatelockableobject(lock
,validatepath(globals
->string
),&cb
,&o
))==0) {
1686 NODE objectnode
=BE2L(o
->be_objectnode
);
1688 if(objectnode
!=ROOTNODE
) {
1690 settemporarylock(objectnode
);
1693 preparecachebuffer(cb
);
1695 if(globals
->packet
->dp_Type
==ACTION_SET_DATE
) {
1696 checksum_writelong_be(cb
->data
, &o
->be_datemodified
, datestamptodate((struct DateStamp
*)globals
->packet
->dp_Arg4
));
1698 // o->datemodified=datestamptodate((struct DateStamp *)packet->dp_Arg4);
1700 else if(globals
->packet
->dp_Type
==ACTION_SET_PROTECT
) {
1701 checksum_writelong_be(cb
->data
, &o
->be_protection
, globals
->packet
->dp_Arg4
^(FIBF_READ
|FIBF_WRITE
|FIBF_EXECUTE
|FIBF_DELETE
));
1703 // o->protection=packet->dp_Arg4^(FIBF_READ|FIBF_WRITE|FIBF_EXECUTE|FIBF_DELETE);
1705 else if(globals
->packet
->dp_Type
==ACTION_SET_OWNER
) {
1706 // ULONG *owner=(ULONG *)&o->owneruid;
1708 checksum_writelong_be(cb
->data
, (ULONG
*)&o
->be_owneruid
, globals
->packet
->dp_Arg4
);
1710 // *owner=packet->dp_Arg4;
1713 o
->bits
=(globals
->packet
->dp_Arg4
& (OTYPE_HIDDEN
|OTYPE_UNDELETABLE
)) | (o
->bits
& ~(OTYPE_HIDDEN
|OTYPE_UNDELETABLE
));
1714 setchecksum(cb
); // new
1717 if((errorcode
=storecachebuffer_nochecksum(cb
))==0) {
1718 struct GlobalHandle
*gh
;
1720 checknotifyforobject(cb
,o
,TRUE
);
1723 if(globals
->packet
->dp_Type
==ACTION_SET_PROTECT
&& (gh
=findglobalhandle(objectnode
))!=0) {
1724 gh
->protection
=globals
->packet
->dp_Arg4
^(FIBF_READ
|FIBF_WRITE
|FIBF_EXECUTE
|FIBF_DELETE
);
1728 deletetransaction();
1732 errorcode
=ERROR_OBJECT_WRONG_TYPE
;
1736 /* this 'loop' will only be left if the disk wasn't full, or
1737 cleanupdeletedfiles() couldn't free up any more space. */
1739 } while(errorcode
==ERROR_DISK_FULL
&& freeupspace()!=FALSE
);
1741 cleartemporarylock();
1744 returnpacket(DOSFALSE
,errorcode
);
1747 returnpacket(DOSTRUE
,0);
1751 case ACTION_SET_FILE_SIZE
:
1752 _DEBUG(("ACTION_SET_FILE_SIZE(0x%08lx,0x%08lx,0x%08lx)\n",globals
->packet
->dp_Arg1
,globals
->packet
->dp_Arg2
,globals
->packet
->dp_Arg3
));
1755 struct ExtFileLock
*lock
=(struct ExtFileLock
*)globals
->packet
->dp_Arg1
;
1759 if(globals
->packet
->dp_Arg3
==OFFSET_BEGINNING
) {
1760 newfilesize
=globals
->packet
->dp_Arg2
;
1762 else if(globals
->packet
->dp_Arg3
==OFFSET_END
) {
1763 newfilesize
=lock
->gh
->size
+globals
->packet
->dp_Arg2
;
1765 else if(globals
->packet
->dp_Arg3
==OFFSET_CURRENT
) {
1766 newfilesize
=lock
->offset
+globals
->packet
->dp_Arg2
;
1769 returnpacket(-1,ERROR_BAD_NUMBER
);
1773 if(newfilesize
>=0) {
1774 ULONG data
=lock
->gh
->data
;
1777 errorcode
=setfilesize(lock
,newfilesize
);
1778 } while(errorcode
==ERROR_DISK_FULL
&& freeupspace()!=FALSE
);
1781 lock
->gh
->data
=data
;
1785 errorcode
=ERROR_SEEK_ERROR
;
1789 returnpacket(lock
->gh
->size
,0);
1792 returnpacket(-1,errorcode
);
1797 _XDEBUG((DEBUG_SEEK
,"ACTION_SEEK(0x%08lx,0x%08lx,0x%08lx)\n",globals
->packet
->dp_Arg1
,globals
->packet
->dp_Arg2
,globals
->packet
->dp_Arg3
));
1800 struct ExtFileLock
*lock
=(struct ExtFileLock
*)globals
->packet
->dp_Arg1
;
1801 struct GlobalHandle
*gh
=lock
->gh
;
1802 ULONG oldpos
=lock
->offset
;
1806 if(globals
->packet
->dp_Arg3
==OFFSET_BEGINNING
) {
1807 newpos
=globals
->packet
->dp_Arg2
;
1809 else if(globals
->packet
->dp_Arg3
==OFFSET_END
) {
1810 newpos
=gh
->size
+globals
->packet
->dp_Arg2
;
1812 else if(globals
->packet
->dp_Arg3
==OFFSET_CURRENT
) {
1813 newpos
=lock
->offset
+globals
->packet
->dp_Arg2
;
1816 returnpacket(-1,ERROR_BAD_NUMBER
);
1820 if(newpos
>=0 && newpos
<=gh
->size
) {
1821 if(newpos
!=oldpos
) {
1822 errorcode
=seek(lock
,newpos
);
1829 errorcode
=ERROR_SEEK_ERROR
;
1833 returnpacket(oldpos
,0);
1836 returnpacket(-1,errorcode
);
1841 _XDEBUG((DEBUG_IO
,"ACTION_READ(0x%08lx,0x%08lx,%ld)\n",globals
->packet
->dp_Arg1
,globals
->packet
->dp_Arg2
,globals
->packet
->dp_Arg3
));
1844 struct ExtFileLock
*lock
=(struct ExtFileLock
*)globals
->packet
->dp_Arg1
;
1845 struct GlobalHandle
*gh
=lock
->gh
;
1846 UBYTE
*buffer
=(UBYTE
*)globals
->packet
->dp_Arg2
;
1848 UBYTE
*startofbuf
=buffer
;
1851 bytesleft
=globals
->packet
->dp_Arg3
;
1852 if(lock
->offset
+bytesleft
> gh
->size
) {
1853 bytesleft
=gh
->size
-lock
->offset
;
1856 if((errorcode
=seektocurrent(lock
))==0) {
1857 if((gh
->protection
& FIBF_READ
)!=0) {
1858 struct CacheBuffer
*extent_cb
;
1859 struct fsExtentBNode
*ebn
;
1861 while(bytesleft
>0 && (errorcode
=findextentbnode(lock
->curextent
, &extent_cb
, &ebn
))==0) {
1863 ULONG offsetinblock
=lock
->extentoffset
& globals
->mask_block
;
1864 BLCK ebn_next
=BE2L(ebn
->be_next
);
1865 UWORD ebn_blocks
=BE2W(ebn
->be_blocks
);
1867 _XDEBUG((DEBUG_IO
,"ACTION_READ: buffer = 0x%p bytesleft = %ld, offsetinblock = %ld, ExtentBNode = %ld, ebn->data = %ld, ebn->blocks = %ld\n",
1868 buffer
, bytesleft
, offsetinblock
, lock
->curextent
, BE2L(ebn
->be_key
), BE2W(ebn
->be_blocks
)));
1870 if(offsetinblock
!=0 || bytesleft
<globals
->bytes_block
) {
1872 // _XDEBUG((DEBUG_IO,"ACTION_READ: nextextentbnode = %ld, extentnodesize = %ld, en->blocks = %ld\n",nextextentbnode,extentnodesize,(ULONG)ebn->blocks));
1874 bytestoread
=globals
->bytes_block
-offsetinblock
;
1876 /* Check if there are more bytes left in the block then we want to read */
1877 if(bytestoread
> bytesleft
) {
1878 bytestoread
=bytesleft
;
1881 if((errorcode
=readbytes(BE2L(ebn
->be_key
)+(lock
->extentoffset
>>globals
->shifts_block
), buffer
, offsetinblock
, bytestoread
))!=0) {
1887 bytestoread
=(((ULONG
)ebn_blocks
)<<globals
->shifts_block
) - lock
->extentoffset
;
1889 /* Check if there are more bytes left in the Extent then we want to read */
1890 if(bytestoread
> bytesleft
) {
1891 bytestoread
=bytesleft
& ~globals
->mask_block
;
1894 if((errorcode
=read(BE2L(ebn
->be_key
)+(lock
->extentoffset
>>globals
->shifts_block
), buffer
, bytestoread
>>globals
->shifts_block
))!=0) {
1899 seekforward(lock
, ebn_blocks
, ebn_next
, bytestoread
);
1901 bytesleft
-=bytestoread
;
1902 buffer
+=bytestoread
;
1904 _XDEBUG((DEBUG_IO
,"ACTION_READ: bytesleft = %ld, errorcode = %ld\n",bytesleft
,errorcode
));
1908 errorcode
=ERROR_READ_PROTECTED
;
1912 _XDEBUG((DEBUG_IO
,"ACTION_READ: errorcode = %ld, buffer = %ld, startofbuf = %ld\n",errorcode
,buffer
,startofbuf
));
1915 returnpacket(-1,errorcode
);
1918 returnpacket(buffer
-startofbuf
,0);
1923 _XDEBUG((DEBUG_IO
,"ACTION_WRITE(0x%08lx,0x%08lx,%ld)\n",globals
->packet
->dp_Arg1
,globals
->packet
->dp_Arg2
,globals
->packet
->dp_Arg3
));
1926 struct ExtFileLock
*lock
=(struct ExtFileLock
*)globals
->packet
->dp_Arg1
;
1927 ULONG bytestowrite
=globals
->packet
->dp_Arg3
;
1931 struct GlobalHandle
*gh
=lock
->gh
;
1933 /* Save some values in case of an error: */
1935 BLCK curextent
=lock
->curextent
;
1936 ULONG extentoffset
=lock
->extentoffset
;
1937 ULONG offset
=lock
->offset
;
1938 ULONG size
=gh
->size
;
1939 ULONG data
=gh
->data
;
1941 if(bytestowrite
!=0) {
1944 if((errorcode
=writetofile(lock
, (UBYTE
*)globals
->packet
->dp_Arg2
, bytestowrite
))==0) {
1948 lock
->curextent
=curextent
;
1949 lock
->extentoffset
=extentoffset
;
1950 lock
->offset
=offset
;
1954 deletetransaction();
1957 } while(errorcode
==ERROR_DISK_FULL
&& freeupspace()!=FALSE
);
1960 _XDEBUG((DEBUG_IO
,"ACTION_WRITE returns (-1, %ld)\n",errorcode
));
1962 returnpacket(-1,errorcode
);
1965 _XDEBUG((DEBUG_IO
,"ACTION_WRITE returns (%ld, 0)\n",bytestowrite
));
1967 lock
->bits
|=EFL_MODIFIED
;
1968 returnpacket(bytestowrite
,0);
1972 case ACTION_FREE_LOCK
:
1973 _XDEBUG((DEBUG_LOCK
,"ACTION_FREE_LOCK\n"));
1978 if((errorcode
=freelock((struct ExtFileLock
*)BADDR(globals
->packet
->dp_Arg1
)))!=0) {
1979 returnpacket(DOSFALSE
,errorcode
);
1982 returnpacket(DOSTRUE
,0);
1985 case ACTION_EXAMINE_ALL
:
1986 _DEBUG(("ACTION_EXAMINE_ALL\n"));
1989 struct ExtFileLock
*lock
;
1990 struct ExAllData
*ead
;
1991 struct ExAllData
*prevead
=0;
1992 struct ExAllControl
*eac
;
1993 struct CacheBuffer
*cb
;
2000 lock
=(struct ExtFileLock
*)BADDR(globals
->packet
->dp_Arg1
);
2001 ead
=(struct ExAllData
*)globals
->packet
->dp_Arg2
;
2002 eac
=(struct ExAllControl
*)globals
->packet
->dp_Arg5
;
2003 spaceleft
=globals
->packet
->dp_Arg3
;
2008 _DEBUG(("ACTION_EXAMINE_ALL: Zero lock was passed in...\n"));
2010 returnpacket(DOSFALSE
,ERROR_OBJECT_WRONG_TYPE
);
2014 if(globals
->packet
->dp_Arg4
>ED_OWNER
) {
2015 returnpacket(DOSFALSE
,ERROR_BAD_NUMBER
);
2019 if(eac
->eac_LastKey
==0) {
2020 if((errorcode
=readobject(lock
->objectnode
,&cb
,&o
))==0) {
2021 if((o
->bits
& OTYPE_DIR
)!=0) {
2022 if(o
->object
.dir
.be_firstdirblock
!=0) {
2023 if((errorcode
=readcachebuffercheck(&cb
,BE2L(o
->object
.dir
.be_firstdirblock
),OBJECTCONTAINER_ID
))==0) {
2024 struct fsObjectContainer
*oc
=cb
->data
;
2027 eac
->eac_LastKey
=BE2L(o
->be_objectnode
);
2031 errorcode
=ERROR_NO_MORE_ENTRIES
;
2035 errorcode
=ERROR_OBJECT_WRONG_TYPE
;
2040 if((errorcode
=readobject(eac
->eac_LastKey
,&cb
,&o
))==ERROR_IS_SOFT_LINK
) {
2045 while(errorcode
==0) {
2046 WORD namelength
=strlen(o
->name
);
2052 switch(globals
->packet
->dp_Arg4
) {
2055 eadsize
+= 4; /* ed_OwnedGID, ed_OwnedUID */
2057 stringsize
+=strlen(o
->name
+namelength
+1)+1;
2058 eadsize
+= sizeof(UBYTE
*); /* ed_Comment */
2060 eadsize
+= 12; /* ed_Ticks, ed_Mins, ed_Days */
2062 eadsize
+= 4; /* ed_Prot */
2064 eadsize
+= 4; /* ed_Size */
2068 stringsize
+= namelength
+1;
2069 eadsize
+= sizeof(APTR
) * 2; /* ed_Name, ed_Next */
2073 // _DEBUG(("ACTION_EXAMINE_ALL: eadsize = %ld, stringsize = %ld, spaceleft = %ld, packet->dp_Arg4 = %ld\n",eadsize,stringsize,spaceleft,packet->dp_Arg4));
2075 if(spaceleft
<eadsize
+stringsize
) {
2079 switch(globals
->packet
->dp_Arg4
) {
2082 ead
->ed_OwnerUID
=BE2W(o
->be_owneruid
);
2083 ead
->ed_OwnerGID
=BE2W(o
->be_ownergid
);
2086 UBYTE
*src
=o
->name
+namelength
+1;
2087 UBYTE
*dest
=(UBYTE
*)ead
+eadsize
;
2089 ead
->ed_Comment
=dest
;
2100 datetodatestamp(BE2L(o
->be_datemodified
),(struct DateStamp
*)&ead
->ed_Days
);
2102 ead
->ed_Prot
=BE2L(o
->be_protection
)^(FIBF_READ
|FIBF_WRITE
|FIBF_EXECUTE
|FIBF_DELETE
);
2104 if((o
->bits
& OTYPE_DIR
)==0) {
2105 ead
->ed_Size
=BE2L(o
->object
.file
.be_size
);
2111 _DEBUG(("examine ED_TYPE, o->bits=%x, o->objectnode=%d\n", o
->bits
, BE2L(o
->be_objectnode
)));
2112 if((o
->bits
& OTYPE_LINK
)!=0) {
2113 ead
->ed_Type
=ST_SOFTLINK
;
2115 if((o
->bits
& OTYPE_DIR
)==0) {
2116 ead
->ed_Type
=ST_FILE
;
2118 else if (o
->be_objectnode
== L2BE(ROOTNODE
)) {
2119 ead
->ed_Type
= ST_ROOT
;
2122 ead
->ed_Type
=ST_USERDIR
;
2127 UBYTE
*dest
=(UBYTE
*)ead
+eadsize
;
2139 // _DEBUG(("Stored entry %s\n",ead->ed_Name));
2143 if(eac
->eac_MatchString
!=0) {
2144 keepentry
=MatchPatternNoCase(eac
->eac_MatchString
,ead
->ed_Name
);
2150 if(keepentry
!=DOSFALSE
&& eac
->eac_MatchFunc
!=0) {
2153 keepentry
=CALLHOOKPKT(eac
->eac_MatchFunc
, ead
, (APTR
)globals
->packet
->dp_Arg4
);
2155 LONG
__asm(*hookfunc
)(register __a0
struct Hook
*,register __a1
struct ExAllData
*,register __a2 ULONG
)=(LONG
__asm(*)(register __a0
struct Hook
*,register __a1
struct ExAllData
*,register __a2 ULONG
))eac
->eac_MatchFunc
->h_Entry
;
2156 keepentry
=hookfunc(eac
->eac_MatchFunc
,ead
,packet
->dp_Arg4
);
2160 if(keepentry
!=DOSFALSE
&& (o
->bits
& OTYPE_HIDDEN
)==0) {
2162 eadsize
= (eadsize
+ sizeof(APTR
) - 1) & ~(sizeof(APTR
) - 1);
2164 prevead
->ed_Next
=ead
;
2167 ead
=(struct ExAllData
*)((UBYTE
*)ead
+eadsize
);
2173 struct fsObjectContainer
*oc
=cb
->data
;
2178 endadr
=(UBYTE
*)oc
+globals
->bytes_block
-sizeof(struct fsObject
)-2;
2180 if((UBYTE
*)o
>=endadr
|| o
->name
[0]==0) {
2181 if(oc
->be_next
!=0) {
2182 if((errorcode
=readcachebuffercheck(&cb
,BE2L(oc
->be_next
),OBJECTCONTAINER_ID
))==0) {
2183 struct fsObjectContainer
*oc
=cb
->data
;
2186 eac
->eac_LastKey
=BE2L(o
->be_objectnode
);
2190 errorcode
=ERROR_NO_MORE_ENTRIES
;
2194 eac
->eac_LastKey
=BE2L(o
->be_objectnode
);
2200 returnpacket(DOSFALSE
,errorcode
);
2203 returnpacket(DOSTRUE
,0);
2207 case ACTION_EXAMINE_NEXT
:
2208 // _DEBUG(("ACTION_EXAMINE_NEXT(0x%08lx,0x%08lx)\n",BADDR(packet->dp_Arg1),BADDR(packet->dp_Arg2)));
2210 /* An entry is added to a directory in the first dir block with
2211 enough space to hold the entry. If there is no space, then
2212 a new block is added at the START of the directory, and the
2213 new entry is added there.
2215 In the directory block with enough space, the entry is added
2216 at the end of the block. The order of directory entries there
2217 fore is like this (square parenthesis indicate blocks):
2221 This means we should scan the directory in the exact opposite
2222 order to avoid a trap when an entry is overwritten during
2223 directory scanning (MODE_NEW_FILE removes old entry, and adds
2224 a new one). See below:
2226 1. [123]; scan is at 1 (next = 2); 1 is overwritten.
2228 2. [231]; scan is at 2 (next = 3); 2 is overwritten.
2230 3. [312]; scan is at 3 (next = 1); 3 is overwritten.
2232 4. [123]; same as 1 -> loop!
2234 By scanning the internals of a dir block backwards the problem
2237 1. [123]; scan is at 3 (next = 2); 3 is overwritten.
2239 2. [123]; scan is at 2 (next = 1); 2 is overwritten.
2241 3. [132]; scan is at 1 (next = next block); 1 is overwritten.
2243 4. new block is loaded -> no loop. */
2246 struct ExtFileLock
*lock
;
2247 struct CacheBuffer
*cb
;
2248 struct FileInfoBlock
*fib
=BADDR(globals
->packet
->dp_Arg2
);
2251 lock
=(struct ExtFileLock
*)BADDR(globals
->packet
->dp_Arg1
);
2254 _DEBUG(("ACTION_EXAMINE_NEXT: Zero lock was passed in...\n"));
2256 returnpacket(DOSFALSE
,ERROR_OBJECT_WRONG_TYPE
);
2261 if(lock->ocblck==0 && lock->ocnode==0) {
2262 _DEBUG(("ACTION_EXAMINE_NEXT: Lock was never passed to EXAMINE_OBJECT or has been re-allocated or the object Examine()d was a file\n"));
2264 returnpacket(DOSFALSE,ERROR_OBJECT_WRONG_TYPE);
2269 if(lock
->currentnode
!=0xFFFFFFFF && fib
->fib_DiskKey
!=lock
->currentnode
) {
2272 /* It looks like the lock was reallocated! In this case we must rebuild
2273 the state information in the lock. lock->currentnode, lock->nextnode
2274 and lock->nextnodeblock. */
2276 if((errorcode
=readobject(fib
->fib_DiskKey
, &cb
, &o
))==0) {
2277 struct fsObjectContainer
*oc
=cb
->data
;
2279 lock
->currentnode
=fib
->fib_DiskKey
;
2281 if((o
=prevobject(o
, oc
))!=0) {
2282 lock
->nextnodeblock
=cb
->blckno
;
2283 lock
->nextnode
=BE2L(o
->be_objectnode
);
2286 lock
->nextnodeblock
=BE2L(oc
->be_next
);
2287 lock
->nextnode
=0xFFFFFFFF;
2292 if(lock
->nextnodeblock
==0) {
2293 errorcode
=ERROR_NO_MORE_ENTRIES
;
2296 /* The passed in lock describes a directory. EXAMINE_NEXT should return
2297 this directory's entries one at the time. The lock has state information
2298 which helps determine at which entry we currently are. */
2300 while(errorcode
==0 && (errorcode
=readcachebuffercheck(&cb
, lock
->nextnodeblock
, OBJECTCONTAINER_ID
))==0) {
2301 struct fsObjectContainer
*oc
=cb
->data
;
2302 struct fsObject
*o
=0;
2305 if(lock
->nextnode
!=0xFFFFFFFF) {
2306 /*** It is possible findobject returns 0... */
2307 o
=findobject(oc
, lock
->nextnode
);
2316 lock
->currentnode
=BE2L(o
->be_objectnode
);
2318 /* prepare for another EXAMINE_NEXT */
2320 /* We need to check if there is another object in this ObjectContainer
2321 following the one we just returned. If there is then return its
2322 node. If there isn't then return the next ObjectContainer ptr and
2323 set ocnode to zero. */
2325 if((o
=prevobject(o
, oc
))!=0) {
2326 /* There IS another object */
2327 lock
->nextnode
=BE2L(o
->be_objectnode
);
2330 lock
->nextnodeblock
=BE2L(oc
->be_next
);
2331 lock
->nextnode
=0xFFFFFFFF;
2334 if((bits
& OTYPE_HIDDEN
)==0) {
2337 else if(lock
->nextnodeblock
==0) {
2338 errorcode
=ERROR_NO_MORE_ENTRIES
;
2344 returnpacket(DOSTRUE
,0);
2347 returnpacket(DOSFALSE
,errorcode
);
2352 /******** OLD EXAMINE_NEXT CODE! */
2353 case ACTION_EXAMINE_NEXT
:
2354 // _DEBUG(("ACTION_EXAMINE_NEXT(0x%08lx,0x%08lx)\n",BADDR(packet->dp_Arg1),BADDR(packet->dp_Arg2)));
2356 /* An entry is added to a directory in the first dir block with
2357 enough space to hold the entry. If there is no space, then
2358 a new block is added at the START of the directory, and the
2359 new entry is added there.
2361 In the directory block with enough space, the entry is added
2362 at the end of the block. The order of directory entries there
2363 fore is like this (square parenthesis indicate blocks):
2367 This means we should scan the directory in the exact opposite
2368 order to avoid a trap when an entry is overwritten during
2369 directory scanning (MODE_NEW_FILE removes old entry, and adds
2370 a new one). See below:
2372 1. [123]; scan is at 1 (next = 2); 1 is overwritten.
2374 2. [231]; scan is at 2 (next = 3); 2 is overwritten.
2376 3. [312]; scan is at 3 (next = 1); 3 is overwritten.
2378 4. [123]; same as 1 -> loop!
2380 By scanning the internals of a dir block backwards the problem
2383 1. [123]; scan is at 3 (next = 2); 3 is overwritten.
2385 2. [123]; scan is at 2 (next = 1); 2 is overwritten.
2387 3. [132]; scan is at 1 (next = next block); 1 is overwritten.
2389 4. new block is loaded -> no loop. */
2392 struct ExtFileLock
*lock
;
2393 struct CacheBuffer
*cb
;
2394 struct FileInfoBlock
*fib
=BADDR(packet
->dp_Arg2
);
2397 lock
=(struct ExtFileLock
*)BADDR(packet
->dp_Arg1
);
2400 _DEBUG(("ACTION_EXAMINE_NEXT: Zero lock was passed in...\n"));
2402 returnpacket(DOSFALSE
,ERROR_OBJECT_WRONG_TYPE
);
2407 if(lock->ocblck==0 && lock->ocnode==0) {
2408 _DEBUG(("ACTION_EXAMINE_NEXT: Lock was never passed to EXAMINE_OBJECT or has been re-allocated or the object Examine()d was a file\n"));
2410 returnpacket(DOSFALSE,ERROR_OBJECT_WRONG_TYPE);
2415 if(lock
->currentnode
!=0xFFFFFFFF && fib
->fib_DiskKey
!=lock
->currentnode
) {
2418 /* It looks like the lock was reallocated! In this case we must rebuild
2419 the state information in the lock. lock->currentnode, lock->nextnode
2420 and lock->nextnodeblock. */
2422 if((errorcode
=readobject(fib
->fib_DiskKey
, &cb
, &o
))==0) {
2423 struct fsObjectContainer
*oc
=cb
->data
;
2425 lock
->currentnode
=fib
->fib_DiskKey
;
2429 if(isobject(o
,oc
)!=FALSE
) {
2430 lock
->nextnodeblock
=cb
->blckno
;
2431 lock
->nextnode
=o
->objectnode
;
2434 lock
->nextnodeblock
=oc
->next
;
2435 lock
->nextnode
=0xFFFFFFFF;
2440 if(lock
->nextnodeblock
==0) {
2441 errorcode
=ERROR_NO_MORE_ENTRIES
;
2444 /* The passed in lock describes a directory. EXAMINE_NEXT should return
2445 this directory's entries one at the time. The lock has state information
2446 which helps determine at which entry we currently are. */
2448 while(errorcode
==0 && (errorcode
=readcachebuffercheck(&cb
,lock
->nextnodeblock
,OBJECTCONTAINER_ID
))==0) {
2449 struct fsObjectContainer
*oc
=cb
->data
;
2450 struct fsObject
*o
=0;
2453 if(lock
->nextnode
!=0xFFFFFFFF) {
2454 /*** It is possible findobject returns 0... */
2455 o
=findobject(oc
,lock
->nextnode
);
2463 lock
->currentnode
=o
->objectnode
;
2465 /* prepare for another EXAMINE_NEXT */
2467 /* We need to check if there is another object in this ObjectContainer
2468 following the one we just returned. If there is then return its
2469 node. If there isn't then return the next ObjectContainer ptr and
2470 set ocnode to zero. */
2474 if(isobject(o
,oc
)!=FALSE
) {
2475 /* There IS another object */
2476 lock
->nextnode
=o
->objectnode
;
2479 lock
->nextnodeblock
=oc
->next
;
2480 lock
->nextnode
=0xFFFFFFFF;
2483 if((bits
& OTYPE_HIDDEN
)==0) {
2486 else if(lock
->nextnodeblock
==0) {
2487 errorcode
=ERROR_NO_MORE_ENTRIES
;
2493 returnpacket(DOSTRUE
,0);
2496 returnpacket(DOSFALSE
,errorcode
);
2502 case ACTION_EXAMINE_OBJECT
:
2503 case ACTION_EXAMINE_FH
:
2504 _DEBUG(("ACTION_EXAMINE_OBJECT\n"));
2507 struct ExtFileLock
*lock
;
2508 struct CacheBuffer
*cb
;
2513 if(globals
->packet
->dp_Type
==ACTION_EXAMINE_OBJECT
) {
2514 lock
=(struct ExtFileLock
*)BADDR(globals
->packet
->dp_Arg1
);
2517 lock
=(struct ExtFileLock
*)globals
->packet
->dp_Arg1
;
2521 objectnode
=ROOTNODE
;
2524 objectnode
=lock
->objectnode
;
2527 errorcode
=readobject(objectnode
,&cb
,&o
);
2528 if(errorcode
==0 || errorcode
==ERROR_IS_SOFT_LINK
) {
2529 fillfib((struct FileInfoBlock
*)BADDR(globals
->packet
->dp_Arg2
),o
);
2531 /* prepare for EXAMINE_NEXT */
2532 if(lock
!=0 && (o
->bits
& OTYPE_DIR
)!=0) {
2533 lock
->currentnode
=0xFFFFFFFF;
2534 lock
->nextnode
=0xFFFFFFFF;
2535 lock
->nextnodeblock
=BE2L(o
->object
.dir
.be_firstdirblock
);
2538 returnpacket(DOSTRUE
,0);
2541 returnpacket(DOSFALSE
,errorcode
);
2547 _DEBUG(("ACTION_INFO\n"));
2550 struct ExtFileLock
*lock
=BADDR(globals
->packet
->dp_Arg1
);
2551 struct InfoData
*id
=BADDR(globals
->packet
->dp_Arg2
);
2553 if(lock
!=0 && globals
->volumenode
!=(struct DeviceList
*)BADDR(lock
->volume
)) {
2554 _DEBUG(("ACTION_INFO: returning error\n"));
2556 returnpacket(DOSFALSE
,ERROR_DEVICE_NOT_MOUNTED
);
2562 returnpacket(DOSTRUE
,0);
2565 case ACTION_MORE_CACHE
:
2566 _DEBUG(("ACTION_MORE_CACHE\n"));
2571 errorcode
=addcachebuffers(globals
->packet
->dp_Arg1
);
2572 _DEBUG(("ACTION_MORE_CACHE: dp_Arg1 = %ld, totalbuffers = %ld, errorcode = %ld\n",globals
->packet
->dp_Arg1
,globals
->totalbuffers
,errorcode
));
2575 // returnpacket(DOSTRUE,totalbuffers);
2577 returnpacket(globals
->totalbuffers
,0);
2580 returnpacket(DOSFALSE
,errorcode
);
2584 case ACTION_CHANGE_MODE
:
2586 struct ExtFileLock
*lock
=0;
2589 if(globals
->packet
->dp_Arg1
==CHANGE_FH
) {
2590 lock
=(struct ExtFileLock
*)((struct FileHandle
*)(BADDR(globals
->packet
->dp_Arg2
)))->fh_Arg1
;
2592 else if(globals
->packet
->dp_Arg1
==CHANGE_LOCK
) {
2593 lock
=BADDR(globals
->packet
->dp_Arg2
);
2597 if(lock
->access
!=globals
->packet
->dp_Arg3
) {
2598 if(lock
->access
!=EXCLUSIVE_LOCK
) {
2599 /* Convert shared lock into an exclusive lock. We need to check
2600 if there are no locks besides this one, and that we aren't
2601 trying to get an exclusive lock on the root (which is never
2604 if(lock
->objectnode
!=ROOTNODE
) {
2605 NODE objectnode
=lock
->objectnode
;
2607 lock
->objectnode
=0; /* this makes sure that our lock is not taken into account by lockable() */
2609 if(lockable(objectnode
,EXCLUSIVE_LOCK
)!=DOSFALSE
) {
2610 /* Lockable says it is possible to lock it exclusively! */
2612 lock
->access
=EXCLUSIVE_LOCK
;
2615 errorcode
=ERROR_OBJECT_IN_USE
;
2618 lock
->objectnode
=objectnode
;
2621 errorcode
=ERROR_OBJECT_IN_USE
;
2625 /* Convert exclusive lock into a shared lock. Should always be
2628 lock
->access
=SHARED_LOCK
;
2633 errorcode
=ERROR_OBJECT_WRONG_TYPE
;
2637 returnpacket(DOSTRUE
,0);
2640 returnpacket(DOSFALSE
,errorcode
);
2645 case ACTION_PARENT_FH
:
2646 _DEBUG(("ACTION_PARENT\n"));
2650 struct ExtFileLock
*lock
;
2652 if(globals
->packet
->dp_Type
==ACTION_PARENT
) {
2653 lock
=(struct ExtFileLock
*)BADDR(globals
->packet
->dp_Arg1
);
2656 lock
=(struct ExtFileLock
*)globals
->packet
->dp_Arg1
;
2659 if(lock
==0 || lock
->objectnode
==ROOTNODE
) {
2664 globals
->string
[0]='/';
2665 globals
->string
[1]=0;
2666 if((errorcode
=lockobject(lock
,globals
->string
,SHARED_LOCK
,&lock
))!=0) {
2667 returnpacket(0,errorcode
);
2670 returnpacket((SIPTR
)TOBADDR(lock
),0);
2674 case ACTION_COPY_DIR
:
2675 case ACTION_COPY_DIR_FH
:
2676 _DEBUG(("ACTION_COPY_DIR\n"));
2680 struct ExtFileLock
*lock
;
2682 if(globals
->packet
->dp_Type
==ACTION_COPY_DIR
) {
2683 lock
=(struct ExtFileLock
*)BADDR(globals
->packet
->dp_Arg1
);
2686 lock
=(struct ExtFileLock
*)globals
->packet
->dp_Arg1
;
2689 _DEBUG(("ACTION_COPY_DIR: lock=%p\n", lock
));
2691 if((errorcode
=lockobject(lock
,"",SHARED_LOCK
,&lock
))!=0) {
2692 _DEBUG(("ACTION_COPY_DIR: Failed to obtain lock!\n"));
2693 returnpacket(0,errorcode
);
2696 returnpacket((SIPTR
)TOBADDR(lock
),0);
2700 case ACTION_LOCATE_OBJECT
:
2702 struct ExtFileLock
*lock
;
2705 copybstrasstr((BSTR
)globals
->packet
->dp_Arg2
,globals
->string
,258);
2707 _XDEBUG((DEBUG_LOCK
,"ACTION_LOCATE_OBJECT(0x%08lx,'%s',0x%08lx)\n",BADDR(globals
->packet
->dp_Arg1
),globals
->string
,globals
->packet
->dp_Arg3
));
2709 if((errorcode
=lockobject((struct ExtFileLock
*)BADDR(globals
->packet
->dp_Arg1
),validatepath(globals
->string
),globals
->packet
->dp_Arg3
,&lock
))!=0) {
2710 returnpacket(0,errorcode
);
2713 returnpacket((SIPTR
)TOBADDR(lock
),0);
2717 case ACTION_SFS_LOCATE_OBJECT
:
2719 struct CacheBuffer
*cb
;
2721 struct ExtFileLock
*lock
=0;
2724 if((errorcode
=readobject(globals
->packet
->dp_Arg1
, &cb
, &o
))==0) {
2725 errorcode
=lockobject2(o
, globals
->packet
->dp_Arg2
, &lock
);
2729 returnpacket(0, errorcode
);
2732 returnpacket((IPTR
)lock
, 0);
2736 case ACTION_ADD_NOTIFY
:
2738 struct NotifyRequest
*nr
;
2740 nr
=(struct NotifyRequest
*)globals
->packet
->dp_Arg1
;
2742 nr
->nr_Next
= (IPTR
)globals
->notifyrequests
;
2744 if (globals
->notifyrequests
)
2745 globals
->notifyrequests
->nr_Prev
= (IPTR
)nr
;
2746 globals
->notifyrequests
= nr
;
2748 _DEBUG(("ACTION_ADD_NOTIFY: Starting notification on %s (flags 0x%08lx)\n",nr
->nr_FullName
,nr
->nr_Flags
));
2750 if((nr
->nr_Flags
& NRF_NOTIFY_INITIAL
)!=0) {
2754 returnpacket(DOSTRUE
,0);
2757 case ACTION_REMOVE_NOTIFY
:
2759 struct NotifyRequest
*nr
;
2761 nr
=(struct NotifyRequest
*)globals
->packet
->dp_Arg1
;
2763 _DEBUG(("ACTION_REMOVE_NOTIFY: Removing notification of %s\n",nr
->nr_FullName
));
2765 if((nr
->nr_Flags
& NRF_SEND_MESSAGE
) != 0) {
2766 /* Removing all outstanding messages form msgport */
2767 while(GetMsg(nr
->nr_stuff
.nr_Msg
.nr_Port
)!=0) {
2773 ((struct NotifyRequest
*)nr
->nr_Prev
)->nr_Next
= nr
->nr_Next
;
2775 globals
->notifyrequests
= (struct NotifyRequest
*)nr
->nr_Next
;
2778 ((struct NotifyRequest
*)nr
->nr_Next
)->nr_Prev
= nr
->nr_Prev
;
2783 returnpacket(DOSTRUE
,0);
2790 if((errorcode
=flushcaches())==0) {
2791 returnpacket(DOSTRUE
, 0);
2794 returnpacket(DOSFALSE
, errorcode
);
2798 case ACTION_SFS_READ_BITMAP
:
2805 errorcode
=extractspace((UBYTE
*)globals
->packet
->dp_Arg1
, globals
->packet
->dp_Arg2
, globals
->packet
->dp_Arg3
);
2807 returnpacket(errorcode
==0 ? DOSTRUE
: DOSFALSE
, errorcode
);
2810 case ACTION_SFS_DEFRAGMENT_INIT
:
2812 globals
->block_defragptr
=2;
2814 returnpacket(DOSTRUE
, 0);
2817 case ACTION_SFS_DEFRAGMENT_STEP
:
2821 globals
->defragmentsteps
=(ULONG
*)globals
->packet
->dp_Arg1
;
2822 globals
->defragmentlongs
=globals
->packet
->dp_Arg2
- 2;
2824 if(globals
->defragmentsteps
!=0) {
2825 *globals
->defragmentsteps
=0;
2828 while((errorcode
=flushtransaction())!=0 && req("Pending buffers couldn't be flushed\nto the disk before defragmentation\nbecause of error %ld.", "Retry|Cancel", errorcode
)==1) {
2835 if((errorcode
=step())!=0) {
2836 deletetransaction();
2841 while((errorcode
=flushtransaction())!=0 && req("Pending buffers couldn't be flushed\nto the disk during defragmentation\nbecause of error %ld.", "Retry|Cancel", errorcode
)==1) {
2847 struct DefragmentStep
*ds
=(struct DefragmentStep
*)globals
->packet
->dp_Arg1
;
2850 if(ds
->id
==AROS_LONG2BE(MAKE_ID('M','O','V','E')) && ds
->length
==3) {
2851 updatelocksaftermove(ds
->data
[1], ds
->data
[2], ds
->data
[0]);
2853 ds
=(struct DefragmentStep
*)((ULONG
*)ds
+ 2 + ds
->length
);
2856 returnpacket(DOSTRUE
, 0);
2859 returnpacket(DOSFALSE
, errorcode
);
2864 _DEBUG(("ERROR_ACTION_NOT_KNOWN (packettype = %ld)\n",globals
->packet
->dp_Type
));
2865 returnpacket(DOSFALSE
,ERROR_ACTION_NOT_KNOWN
);
2869 else if(globals
->disktype
==ID_NO_DISK_PRESENT
) {
2870 dumppackets(globals
->packet
,ERROR_NO_DISK
);
2873 dumppackets(globals
->packet
,ERROR_NOT_A_DOS_DISK
);
2885 static void fillfib(struct FileInfoBlock
*fib
,struct fsObject
*o
)
2891 if (o
->be_objectnode
==L2BE(ROOTNODE
)) {
2892 fib
->fib_DirEntryType
=ST_ROOT
;
2893 fib
->fib_Size
=BE2L(o
->object
.file
.be_size
);
2894 fib
->fib_NumBlocks
=(BE2L(o
->object
.file
.be_size
)+globals
->bytes_block
-1) >> globals
->shifts_block
;
2895 } else if((o
->bits
& OTYPE_LINK
)!=0) {
2896 fib
->fib_DirEntryType
=ST_SOFTLINK
;
2897 // fib->fib_DirEntryType=ST_USERDIR; // For compatibility with Diavolo 3.4 -> screw it, DOpus fails...
2898 fib
->fib_Size
=BE2L(o
->object
.file
.be_size
);
2899 fib
->fib_NumBlocks
=0;
2901 else if((o
->bits
& OTYPE_DIR
)==0) {
2902 fib
->fib_DirEntryType
=ST_FILE
;
2903 fib
->fib_Size
=BE2L(o
->object
.file
.be_size
);
2904 fib
->fib_NumBlocks
=(BE2L(o
->object
.file
.be_size
)+globals
->bytes_block
-1) >> globals
->shifts_block
;
2907 fib
->fib_DirEntryType
=ST_USERDIR
;
2909 fib
->fib_NumBlocks
=1;
2911 fib
->fib_Protection
=BE2L(o
->be_protection
)^(FIBF_READ
|FIBF_WRITE
|FIBF_EXECUTE
|FIBF_DELETE
);
2912 fib
->fib_EntryType
=fib
->fib_DirEntryType
;
2913 fib
->fib_DiskKey
=BE2L(o
->be_objectnode
);
2914 fib
->fib_OwnerUID
=BE2W(o
->be_owneruid
);
2915 fib
->fib_OwnerGID
=BE2W(o
->be_ownergid
);
2916 datetodatestamp(BE2L(o
->be_datemodified
),&fib
->fib_Date
);
2919 dest
= fib
->fib_FileName
;
2927 fib
->fib_FileName
[0]=length
;
2929 src
++; /* comment follows name, so just skip the null-byte seperating them */
2931 dest
= fib
->fib_Comment
;
2939 fib
->fib_Comment
[0]=length
;
2944 static struct DosPacket
*getpacket(struct Process
*p
) {
2945 struct MsgPort
*port
=&p
->pr_MsgPort
; /* get port of our process */
2946 struct Message
*msg
;
2948 if((msg
=GetMsg(port
))!=0) {
2949 return((struct DosPacket
*)msg
->mn_Node
.ln_Name
);
2958 static struct DosPacket
*waitpacket(struct Process
*p
) {
2959 struct MsgPort
*port
=&p
->pr_MsgPort
; /* get port of our process */
2960 struct Message
*msg
;
2966 return((struct DosPacket
*)msg
->mn_Node
.ln_Name
);
2971 static void returnpacket(SIPTR res1
,LONG res2
) {
2972 struct Message
*msg
;
2973 struct MsgPort
*replyport
;
2975 globals
->packet
->dp_Res1
=res1
; /* set return codes */
2976 globals
->packet
->dp_Res2
=res2
;
2978 replyport
=globals
->packet
->dp_Port
; /* Get ReplyPort */
2980 msg
=globals
->packet
->dp_Link
; /* Pointer to the Exec-Message of the packet */
2982 globals
->packet
->dp_Port
=&globals
->mytask
->pr_MsgPort
; /* Setting Packet-Port back */
2984 msg
->mn_Node
.ln_Name
=(char *)globals
->packet
; /* Connect Message and Packet */
2985 msg
->mn_Node
.ln_Succ
=NULL
;
2986 msg
->mn_Node
.ln_Pred
=NULL
;
2988 PutMsg(replyport
,msg
); /* Send the Message */
2993 static void returnpacket2(struct DosPacket
*packet
, SIPTR res1
, LONG res2
)
2995 struct Message
*msg
;
2996 struct MsgPort
*replyport
;
2998 D(bug("[SFS] Replying, results are %ld/%ld\n", res1
, res2
));
3000 packet
->dp_Res1
=res1
; /* set return codes */
3001 packet
->dp_Res2
=res2
;
3003 replyport
=packet
->dp_Port
; /* Get ReplyPort */
3005 msg
=packet
->dp_Link
; /* Pointer to the Exec-Message of the packet */
3007 packet
->dp_Port
=&globals
->mytask
->pr_MsgPort
; /* Setting Packet-Port back */
3009 msg
->mn_Node
.ln_Name
=(char *)packet
; /* Connect Message and Packet */
3010 msg
->mn_Node
.ln_Succ
=NULL
;
3011 msg
->mn_Node
.ln_Pred
=NULL
;
3013 PutMsg(replyport
,msg
); /* Send the Message */
3018 void starttimeout() {
3019 /* From the AbortIO AutoDocs:
3020 iORequest - pointer to an I/O request block (must have been used
3021 at least once. May be active or finished). */
3023 if(globals
->pendingchanges
==FALSE
) {
3024 globals
->inactivitytimer_ioreq
->tr_time
.tv_secs
=globals
->inactivity_timeout
/2;
3025 globals
->inactivitytimer_ioreq
->tr_time
.tv_micro
=(globals
->inactivity_timeout
*500000)%1000000;
3026 globals
->inactivitytimer_ioreq
->tr_node
.io_Command
=TR_ADDREQUEST
;
3028 SendIO(&globals
->inactivitytimer_ioreq
->tr_node
);
3030 globals
->pendingchanges
=TRUE
;
3031 globals
->timerreset
=FALSE
;
3034 globals
->timerreset
=TRUE
; /* Indicates that during the timeout there was another request. */
3037 if(globals
->activitytimeractive
==FALSE
) {
3038 globals
->activitytimer_ioreq
->tr_time
.tv_secs
=globals
->activity_timeout
;
3039 globals
->activitytimer_ioreq
->tr_time
.tv_micro
=0;
3040 globals
->activitytimer_ioreq
->tr_node
.io_Command
=TR_ADDREQUEST
;
3042 SendIO(&globals
->activitytimer_ioreq
->tr_node
);
3044 globals
->activitytimeractive
=TRUE
;
3050 void stoptimeout(void) {
3052 if(globals
->pendingchanges
!=FALSE
) {
3053 AbortIO(&globals
->inactivitytimer_ioreq
->tr_node
);
3054 WaitIO(&globals
->inactivitytimer_ioreq
->tr_node
);
3056 globals
->pendingchanges
=FALSE
;
3057 globals
->timerreset
=FALSE
;
3060 // if(activitytimeractive!=FALSE) {
3061 // AbortIO(&activitytimer_ioreq->tr_node);
3062 // WaitIO(&activitytimer_ioreq->tr_node);
3064 // activitytimeractive=FALSE;
3070 LONG
flushcaches() {
3073 /* Flushes any pending changes to disk and ask the user what to do when
3076 while((errorcode
=flushtransaction())!=0 && req("Pending buffers couldn't be flushed\nto the disk because of error %ld.", "Retry|Cancel", errorcode
)==1) {
3086 void invalidatecaches() {
3088 /* Invalidates all caches without flushing. Call flushcaches()
3091 invalidatecachebuffers();
3092 invalidateiocaches();
3097 LONG
readroots(void)
3099 struct CacheBuffer
*cb1
;
3100 struct CacheBuffer
*cb2
;
3101 struct fsRootBlock
*rb1
;
3102 struct fsRootBlock
*rb2
;
3108 if((errorcode
=readcachebuffer(&cb1
,0))!=0) {
3112 lockcachebuffer(cb1
);
3114 if((errorcode
=readcachebuffer(&cb2
,globals
->blocks_total
-1))!=0) {
3115 unlockcachebuffer(cb1
);
3119 unlockcachebuffer(cb1
);
3124 if(checkchecksum(cb1
)==DOSFALSE
|| rb1
->bheader
.id
!=L2BE(DOSTYPE_ID
) || rb1
->bheader
.be_ownblock
!=0) {
3125 _DEBUG(("cb1/rb1 not ok!\n"));
3129 _DEBUG(("checkchecksum(cb1)=%d, rb1->bheader.id=%08x (wanted %08x), rb1->bheader.ownblock=%d\n",
3130 checkchecksum(cb1
),BE2L(rb1
->bheader
.id
), DOSTYPE_ID
, BE2L(rb1
->bheader
.be_ownblock
)
3133 if(checkchecksum(cb2
)==DOSFALSE
|| rb2
->bheader
.id
!=L2BE(DOSTYPE_ID
) || BE2L(rb2
->bheader
.be_ownblock
)!=BE2L(rb2
->be_totalblocks
)-1) {
3134 _DEBUG(("cb2/rb2 not ok!\n"));
3138 _DEBUG(("checkchecksum(cb2)=%d, rb2->bheader.id=%08x, rb2->bheader.ownblock=%d, rb2->be_totalblocks =%d\n",
3139 checkchecksum(cb2
),BE2L(rb2
->bheader
.id
), BE2L(rb2
->bheader
.be_ownblock
), BE2L(rb2
->be_totalblocks
)
3142 if(rb1okay
!=FALSE
&& rb2okay
!=FALSE
) {
3143 /* Both root blocks look okay. */
3146 if(rb1->sequencenumber!=rb2->sequencenumber) {
3147 // Sequence numbers differ!
3151 /* Check sizes stored in rootblock */
3152 if ((rb1
->be_blocksize
!= L2BE(globals
->bytes_block
)) || (rb1
->be_totalblocks
!=L2BE(globals
->blocks_total
)))
3154 _DEBUG(("bad size in rb1!\n"));
3155 return(ERROR_NOT_A_DOS_DISK
);
3159 * Historically SFS rootblock holds absolute start and end positions on the disk in bytes.
3160 * They are used for validation and nothing else.
3161 * However, a situation is possible when for example someone takes an image of SFS partition
3162 * and then tries to mount it.
3163 * In order to make it working we compare lengths, not positions. If length is okay, the rootblock
3164 * is assumed to be okay.
3166 first
= ((UQUAD
)BE2L(rb1
->be_firstbyteh
) << 32) | BE2L(rb1
->be_firstbyte
);
3167 last
= ((UQUAD
)BE2L(rb1
->be_lastbyteh
) << 32) | BE2L(rb1
->be_lastbyte
);
3169 if (last
- first
!= globals
->byte_high
- globals
->byte_low
)
3171 _DEBUG(("bad value in rb1!\n"));
3172 return ERROR_NOT_A_DOS_DISK
;
3175 if(rb1
->be_version
!=BE2W(STRUCTURE_VERSION
)) {
3176 /* Different version! */
3178 request(PROGRAMNAME
" request","%s\n"\
3179 "is in a format unsupported by this version\n"\
3180 "of the filesystem. Please reformat the disk or\n"\
3181 "install the correct version of this filesystem.",
3182 "Ok",AROS_BSTR_ADDR(globals
->devnode
->dn_Name
));
3184 return(ERROR_NOT_A_DOS_DISK
);
3187 globals
->block_bitmapbase
=BE2L(rb1
->be_bitmapbase
);
3188 globals
->block_adminspace
=BE2L(rb1
->be_adminspacecontainer
);
3189 globals
->block_root
=BE2L(rb1
->be_rootobjectcontainer
);
3190 globals
->block_extentbnoderoot
=BE2L(rb1
->be_extentbnoderoot
);
3191 globals
->block_objectnoderoot
=BE2L(rb1
->be_objectnoderoot
);
3193 if((rb1
->bits
& ROOTBITS_CASESENSITIVE
)!=0) {
3194 globals
->is_casesensitive
=TRUE
;
3197 globals
->is_casesensitive
=FALSE
;
3200 if((rb1
->bits
& ROOTBITS_RECYCLED
)!=0) {
3201 globals
->has_recycled
=TRUE
;
3204 globals
->has_recycled
=FALSE
;
3208 errorcode
=ERROR_NOT_A_DOS_DISK
;
3216 struct DeviceList
*usevolumenode(UBYTE
*name
, ULONG creationdate
) {
3217 struct DosList
*dol
;
3218 struct DeviceList
*vn
=0;
3220 /* This function locates the specified volumenode, and if found
3221 uses it for the current volume inserted. If the node is not
3222 found this function returns 0. If the specified volumenode
3223 is found, but is found to be in use, then this function
3224 returns -1. Otherwise the found volumenode is returned. */
3226 dol
=LockDosList(LDF_READ
|LDF_VOLUMES
);
3228 while((dol
=FindDosEntry(dol
, name
, LDF_VOLUMES
))!=0) {
3229 if(datestamptodate(&dol
->dol_misc
.dol_volume
.dol_VolumeDate
)==creationdate
) { // Do volumes have same creation date?
3231 if(dol
->dol_misc
.dol_volume
.dol_LockList
!=0 || ((struct DeviceList
*)dol
)->dl_unused
!=0) { // Is volume not in use?
3232 struct NotifyRequest
*nr
;
3233 struct ExtFileLock
*lock
;
3235 /* Volume is not currently in use, so grab locklist & notifyrequests and patch fl_Task fields */
3237 _DEBUG(("usevolumenode: Found DosEntry with same date, and locklist!=0\n"));
3239 lock
=(struct ExtFileLock
*)BADDR(dol
->dol_misc
.dol_volume
.dol_LockList
);
3240 nr
=(struct NotifyRequest
*)BADDR((((struct DeviceList
*)dol
)->dl_unused
));
3241 dol
->dol_misc
.dol_volume
.dol_LockList
=0;
3242 ((struct DeviceList
*)dol
)->dl_unused
=0;
3246 globals
->locklist
=lock
;
3247 globals
->notifyrequests
=nr
;
3250 lock
->task
=&globals
->mytask
->pr_MsgPort
;
3255 nr
->nr_Handler
=&globals
->mytask
->pr_MsgPort
;
3256 nr
= (struct NotifyRequest
*)nr
->nr_Next
;
3259 vn
=(struct DeviceList
*)dol
;
3265 _DEBUG(("usevolumenode: Found DosEntry with same date, but it is in use!\n"));
3267 vn
=(struct DeviceList
*)-1;
3271 /* Volume nodes are of different date, continue search */
3272 dol
=NextDosEntry(dol
, LDF_VOLUMES
);
3275 UnLockDosList(LDF_READ
|LDF_VOLUMES
);
3284 /* This routine is called whenever a disk has changed (via ACTION_INHIBIT or
3285 on startup). The routine scans the disk and initializes the necessary
3288 - Check if the disk is a valid DOS disk
3289 If so, get name and datestamp of the disk
3290 If valid, look for volume node of the same name and datestamp
3291 If so, retrieve locklist from dol_LockList (fix fl_Task fields!)
3292 and use existing volume node.
3293 If not, a new volume node is created.
3294 If the disk carries the same attributes as another ACTIVE volume
3295 the handler ignores the newly inserted volume.
3296 If not valid, R/W error requester -> "NDOS"
3297 If not valid type is "NDOS"
3301 changegeometry(globals
->dosenvec
);
3303 if(globals
->volumenode
==0) {
3304 struct CacheBuffer
*cb
;
3305 struct fsObjectContainer
*oc
=0;
3309 globals
->diskstate
=writeprotection();
3311 if((errorcode
=readroots())==0) {
3313 /* Root blocks are valid for this filesystem */
3315 _DEBUG(("Initdisk: Root blocks read\n"));
3318 dreq("Root blocks are okay!");
3321 if((errorcode
=checkfortransaction())==0) {
3323 _DEBUG(("Initdisk: Checked for an old Transaction and applied it if it was present.\n"));
3325 if((errorcode
=readcachebuffercheck(&cb
,globals
->block_root
,OBJECTCONTAINER_ID
))==0) {
3326 struct fsRootInfo
*ri
=(struct fsRootInfo
*)((UBYTE
*)cb
->data
+globals
->bytes_block
-sizeof(struct fsRootInfo
));
3329 lockcachebuffer(cb
);
3332 _DEBUG(("Initdisk: '%s' was inserted\n",oc
->object
[0].name
));
3334 /* ROOT block is valid for this filesystem */
3336 /* We should count the number of set bits in the bitmap now */
3339 struct CacheBuffer
*cb
;
3341 BLCK bitmapblock
=globals
->block_bitmapbase
;
3342 UWORD cnt
=globals
->blocks_bitmap
;
3345 while(cnt
-->0 && (errorcode
=readcachebuffercheck(&cb
,bitmapblock
,BITMAP_ID
))==0) {
3348 for(n
=0; n
<((globals
->bytes_block
-sizeof(struct fsBitmap
))>>2); n
++) {
3349 if(b
->bitmap
[n
]!=0) {
3350 if(b
->bitmap
[n
]==0xFFFFFFFF) {
3354 blocksfree
+=bfcnto(b
->bitmap
[n
]);
3362 unlockcachebuffer(cb
);
3364 _DEBUG(("Initdisk: Traversed bitmap, found %ld free blocks\n",blocksfree
));
3366 if(errorcode
==0 && BE2L(ri
->be_freeblocks
)!=blocksfree
) {
3367 if(ri
->be_freeblocks
!=0) {
3368 dreq("The number of free blocks (%ld) is incorrect.\n"\
3369 "According to the bitmap it should be %ld.\n"\
3370 "The number of free blocks will now be updated.", BE2L(ri
->be_freeblocks
), blocksfree
);
3375 preparecachebuffer(cb
);
3377 ri
->be_freeblocks
=L2BE(blocksfree
);
3379 if((errorcode
=storecachebuffer(cb
))==0) {
3383 deletetransaction();
3388 _DEBUG(("Initdisk: A valid DOS disk\n"));
3390 newdisktype
= DOSTYPE_ID
;
3393 dreq("There is a valid SFS disk present!");
3399 dreq("SFS disk is invalid; bitmap error.");
3402 newdisktype
=ID_NOT_REALLY_DOS
;
3403 errorcode
=ERROR_NOT_A_DOS_DISK
;
3409 dreq("SFS disk is invalid; root objectcontainer error.");
3412 newdisktype
=ID_NOT_REALLY_DOS
;
3413 errorcode
=ERROR_NOT_A_DOS_DISK
;
3419 dreq("SFS disk is invalid; transaction error.");
3422 newdisktype
=ID_NOT_REALLY_DOS
;
3423 errorcode
=ERROR_NOT_A_DOS_DISK
;
3426 else if(errorcode
==INTERR_CHECKSUM_FAILURE
|| errorcode
==ERROR_NOT_A_DOS_DISK
) {
3427 newdisktype
=ID_NOT_REALLY_DOS
;
3428 errorcode
=ERROR_NOT_A_DOS_DISK
;
3431 dreq("SFS disk is invalid; checksum failure.");
3434 else if(errorcode
==INTERR_BLOCK_WRONG_TYPE
) {
3436 dreq("SFS disk is invalid; wrong block type.");
3439 newdisktype
=ID_NOT_REALLY_DOS
;
3440 errorcode
=ERROR_NOT_A_DOS_DISK
;
3442 else if(errorcode
==TDERR_DiskChanged
) {
3444 dreq("SFS disk is invalid; disk was changed.");
3447 newdisktype
=ID_NO_DISK_PRESENT
;
3448 errorcode
=ERROR_NO_DISK
;
3452 dreq("SFS disk is invalid; unreadable disk.");
3455 newdisktype
=ID_UNREADABLE_DISK
;
3456 errorcode
=ERROR_NOT_A_DOS_DISK
;
3460 struct DeviceList
*vn
;
3461 struct fsRootInfo
*ri
=(struct fsRootInfo
*)((UBYTE
*)oc
+globals
->bytes_block
-sizeof(struct fsRootInfo
));
3463 _DEBUG(("initdisk: Checking for an existing volume-node\n"));
3465 if((vn
=usevolumenode(oc
->object
[0].name
, BE2L(ri
->be_datecreated
)))!=(struct DeviceList
*)-1) {
3467 /* VolumeNode was not found, so we need to create a new one. */
3469 _DEBUG(("initdisk: No volume-node found, creating new one instead.\n"));
3471 if((vn
=(struct DeviceList
*)MakeDosEntry(" ",DLT_VOLUME
))!=0) {
3472 struct SFSMessage
*sfsm
;
3473 UBYTE
*d2
=(UBYTE
*)BADDR(vn
->dl_Name
);
3474 #ifdef AROS_FAST_BSTR
3475 copystr(oc
->object
[0].name
, d2
, 30);
3478 UBYTE
*s
=oc
->object
[0].name
;
3481 while(*s
!=0 && len
<30) {
3490 datetodatestamp(BE2L(ri
->be_datecreated
), &vn
->dl_VolumeDate
);
3492 _DEBUG(("initdisk: Sending msg.\n"));
3494 if((sfsm
=AllocVec(sizeof(struct SFSMessage
), MEMF_CLEAR
))!=0) {
3495 sfsm
->command
=SFSM_ADD_VOLUMENODE
;
3496 sfsm
->data
=(IPTR
)vn
;
3497 sfsm
->msg
.mn_Length
=sizeof(struct SFSMessage
);
3499 PutMsg(globals
->sdlhport
, (struct Message
*)sfsm
);
3503 errorcode
=ERROR_NO_FREE_STORE
;
3507 _DEBUG(("initdisk: Using new or old volumenode.\n"));
3509 if(errorcode
==0) { /* Reusing the found VolumeNode or using the new VolumeNode */
3510 vn
->dl_Task
=globals
->devnode
->dn_Task
;
3511 vn
->dl_DiskType
=globals
->dosenvec
->de_DosType
;
3512 globals
->volumenode
=vn
;
3515 else { /* Volume is in use by another handler -- stay off */
3516 _DEBUG(("Initdisk: Found DosEntry with same date, and locklist==0\n"));
3517 newdisktype
=ID_NO_DISK_PRESENT
; /* Hmmm... EXTREMELY unlikely, but may explain the strange bug Laire had. */
3518 errorcode
=ERROR_NO_DISK
;
3520 globals
->volumenode
=0;
3525 diskchangenotify(IECLASS_DISKINSERTED
);
3528 globals
->disktype
=newdisktype
;
3539 static struct DosList
*attemptlockdoslist(LONG tries
, LONG delay
) {
3540 struct DosList
*dol
;
3541 struct DosPacket
*dp
;
3544 dol
=AttemptLockDosList(LDF_WRITE
|LDF_VOLUMES
);
3546 if(((IPTR
)dol
& ~1)!=0) {
3554 if((dp
=getpacket(globals
->mytask
))!=0) {
3555 if(handlesimplepackets(dp
)==0) {
3556 dumppackets(dp
, ERROR_NOT_A_DOS_DISK
);
3566 void removevolumenode(struct DosList
*dol
, struct DosList
*vn
) {
3567 while((dol
=NextDosEntry(dol
, LDF_VOLUMES
))!=0) {
3576 static void deinitdisk() {
3578 /* This function flushes all caches, and then invalidates them.
3579 If successful, this function then proceeds to either remove
3580 the volumenode, or transfer any outstanding locks/notifies to
3581 it. Finally it notifies the system of the disk removal. */
3583 _DEBUG(("deinitdisk: entry\n"));
3588 if(globals
->volumenode
!=0) {
3590 /* We first check if the VolumeNode needs to be removed; if not
3591 then we do not lock the DosList and modify some of its fields.
3592 If it must be removed, we first attempt to lock the DosList
3593 synchronously; whether this fails or not, we always send a
3594 removal message to the DosList subtask. */
3596 if(globals
->locklist
!=0 || globals
->notifyrequests
!=0) {
3598 /* There are locks or notifyrequests, so we cannot kill the volumenode. */
3600 /* We haven't got the DosList locked here, but I think it is fairly
3601 safe to modify these fields directly. */
3605 globals
->volumenode
->dl_Task
=0;
3606 globals
->volumenode
->dl_LockList
=MKBADDR(globals
->locklist
);
3607 globals
->volumenode
->dl_unused
=MKBADDR(globals
->notifyrequests
);
3611 globals
->locklist
=0;
3612 globals
->notifyrequests
=0;
3615 struct SFSMessage
*sfsm
;
3616 struct DosList
*dol
=attemptlockdoslist(5, 1);
3618 _DEBUG(("deinitdisk: dol = %ld\n", dol
));
3620 if(dol
!=0) { /* Is DosList locked? */
3621 removevolumenode(dol
, (struct DosList
*)globals
->volumenode
);
3622 UnLockDosList(LDF_WRITE
|LDF_VOLUMES
);
3625 _DEBUG(("deinitdisk: sending msg\n"));
3627 /* Even if we succesfully locked the DosList, we still should notify
3628 the DosList task to remove the node as well (and to free it), just
3629 in case a VolumeNode Add was still pending. */
3631 if((sfsm
=AllocVec(sizeof(struct SFSMessage
), MEMF_CLEAR
))!=0) {
3632 sfsm
->command
=SFSM_REMOVE_VOLUMENODE
;
3633 sfsm
->data
=(IPTR
)globals
->volumenode
;
3634 sfsm
->msg
.mn_Length
=sizeof(struct SFSMessage
);
3636 PutMsg(globals
->sdlhport
, (struct Message
*)sfsm
);
3640 _DEBUG(("deinitdisk: done\n"));
3642 globals
->volumenode
=0;
3644 diskchangenotify(IECLASS_DISKREMOVED
);
3650 LONG
handlesimplepackets(struct DosPacket
*packet
) {
3651 LONG type
=packet
->dp_Type
; /* After returnpacket, packet->dp_Type is invalid! */
3653 switch(packet
->dp_Type
) {
3654 case ACTION_IS_FILESYSTEM
:
3655 returnpacket2(packet
, DOSTRUE
,0);
3658 case ACTION_GET_DISK_FSSM
:
3659 returnpacket2(packet
, (LONG
)startupmsg
,0);
3661 case ACTION_FREE_DISK_FSSM
:
3662 returnpacket2(packet
, DOSTRUE
,0);
3665 case ACTION_DISK_INFO
:
3666 actiondiskinfo(packet
);
3668 case ACTION_SAME_LOCK
:
3669 actionsamelock(packet
);
3671 case ACTION_CURRENT_VOLUME
:
3672 actioncurrentvolume(packet
);
3683 static LONG
dumppackets(struct DosPacket
*packet
,LONG returncode
) {
3684 LONG type
=packet
->dp_Type
; /* After returnpacket, packet->dp_Type is invalid! */
3686 /* Routine which returns ERROR_NOT_A_DOS_DISK for all known
3687 packets which cannot be handled under such a situation */
3693 case ACTION_SET_FILE_SIZE
:
3694 returnpacket2(packet
, -1,returncode
);
3696 case ACTION_CREATE_DIR
:
3697 case ACTION_FINDUPDATE
:
3698 case ACTION_FINDINPUT
:
3699 case ACTION_FINDOUTPUT
:
3701 case ACTION_EXAMINE_OBJECT
:
3702 case ACTION_EXAMINE_NEXT
:
3703 case ACTION_COPY_DIR
:
3704 case ACTION_LOCATE_OBJECT
:
3705 case ACTION_PARENT
: /* till here verified to return 0 on error! */
3706 case ACTION_LOCK_RECORD
:
3707 case ACTION_FREE_RECORD
:
3708 case ACTION_FREE_LOCK
:
3709 case ACTION_CHANGE_MODE
:
3710 case ACTION_FH_FROM_LOCK
:
3711 case ACTION_COPY_DIR_FH
:
3712 case ACTION_PARENT_FH
:
3713 case ACTION_EXAMINE_FH
:
3714 case ACTION_EXAMINE_ALL
:
3715 case ACTION_DELETE_OBJECT
:
3716 case ACTION_RENAME_OBJECT
:
3717 case ACTION_MAKE_LINK
:
3718 case ACTION_READ_LINK
:
3719 case ACTION_SET_COMMENT
:
3720 case ACTION_SET_DATE
:
3721 case ACTION_SET_PROTECT
:
3723 case ACTION_RENAME_DISK
:
3724 case ACTION_SERIALIZE_DISK
:
3726 case ACTION_GET_DISK_FSSM
:
3728 case ACTION_MORE_CACHE
:
3729 case ACTION_WRITE_PROTECT
:
3730 case ACTION_ADD_NOTIFY
:
3731 case ACTION_REMOVE_NOTIFY
:
3732 case ACTION_INHIBIT
: /* These packets are only dumped when doslist is locked */
3734 returnpacket2(packet
, DOSFALSE
,returncode
);
3737 returnpacket2(packet
, DOSFALSE
,ERROR_ACTION_NOT_KNOWN
);
3746 static void dumppacket() {
3747 struct DosPacket
*packet
;
3749 /* routine which gets a packet and returns ERROR_NOT_A_DOS_DISK for all
3750 known packets which cannot be executed while we are attempting to access
3751 the doslist. Some packets which don't require disk access will be
3752 handled as normal. */
3754 packet
=waitpacket(globals
->mytask
);
3756 if(handlesimplepackets(packet
)==0) {
3757 dumppackets(packet
,ERROR_NOT_A_DOS_DISK
);
3763 static void actioncurrentvolume(struct DosPacket
*packet
) {
3764 struct ExtFileLock
*lock
=(struct ExtFileLock
*)packet
->dp_Arg1
;
3766 _DEBUG(("ACTION_CURRENT_VOLUME(%ld)\n",lock
));
3769 _DEBUG(("ACTION_CURRENT_VOLUME: volumenode = %ld\n",globals
->volumenode
));
3770 returnpacket2(packet
, (SIPTR
)TOBADDR(globals
->volumenode
), 0);
3773 returnpacket2(packet
, (SIPTR
)lock
->volume
,0);
3779 static void actionsamelock(struct DosPacket
*packet
) {
3780 struct ExtFileLock
*lock
;
3781 struct ExtFileLock
*lock2
;
3783 lock
=(struct ExtFileLock
*)BADDR(packet
->dp_Arg1
);
3784 lock2
=(struct ExtFileLock
*)BADDR(packet
->dp_Arg2
);
3786 if(lock
->objectnode
==lock2
->objectnode
&& lock
->task
==lock2
->task
) {
3787 returnpacket2(packet
, DOSTRUE
,0);
3790 returnpacket2(packet
, DOSFALSE
,0);
3795 static void actiondiskinfo(struct DosPacket
*packet
) {
3796 struct InfoData
*id
=BADDR(packet
->dp_Arg1
);
3798 _DEBUG(("ACTION_DISK_INFO\n"));
3802 returnpacket2(packet
, DOSTRUE
,0);
3807 static void fillinfodata(struct InfoData
*id
) {
3810 id
->id_NumSoftErrors
=globals
->numsofterrors
;
3811 id
->id_UnitNumber
=globals
->startupmsg
->fssm_Unit
;
3812 id
->id_DiskState
=globals
->diskstate
;
3813 id
->id_NumBlocks
=globals
->blocks_total
-globals
->blocks_reserved_start
-globals
->blocks_reserved_end
;
3815 usedblocks
=id
->id_NumBlocks
;
3817 if(globals
->disktype
== DOSTYPE_ID
) {
3818 ULONG deletedfiles
, deletedblocks
;
3820 getusedblocks(&usedblocks
);
3821 if(getrecycledinfo(&deletedfiles
, &deletedblocks
)==0) {
3822 usedblocks
-=deletedblocks
;
3826 id
->id_NumBlocksUsed
=usedblocks
;
3827 id
->id_BytesPerBlock
=globals
->bytes_block
;
3828 id
->id_DiskType
=globals
->disktype
;
3830 D(kprintf("Filling InfoData structure with a volumenode ptr to address %ld. Disktype = 0x%08lx\n", globals
->volumenode
, globals
->disktype
));
3832 id
->id_VolumeNode
=TOBADDR(globals
->volumenode
);
3834 _DEBUG(("fillinfodata: volumenode = %ld, disktype = 0x%08lx\n", globals
->volumenode
, globals
->disktype
));
3836 if(globals
->locklist
!=0) {
3837 id
->id_InUse
=DOSTRUE
;
3840 id
->id_InUse
=DOSFALSE
;
3846 BOOL
checkchecksum(struct CacheBuffer
*cb
) {
3847 #ifdef CHECKCHECKSUMSALWAYS
3848 if(CALCCHECKSUM(globals
->bytes_block
,cb
->data
)==0) {
3850 if((cb
->bits
& CB_CHECKSUM
)!=0 || CALCCHECKSUM(globals
->bytes_block
,cb
->data
)==0) { // -> copycachebuffer screws this up!
3852 cb
->bits
|=CB_CHECKSUM
;
3860 void setchecksum(struct CacheBuffer
*cb
) {
3861 struct fsBlockHeader
*bh
=cb
->data
;
3863 bh
->be_checksum
=0; /* Important! */
3864 bh
->be_checksum
=L2BE(-CALCCHECKSUM(globals
->bytes_block
,cb
->data
));
3869 LONG
readcachebuffercheck(struct CacheBuffer
**returnedcb
,ULONG blckno
,ULONG type
) {
3871 struct fsBlockHeader
*bh
;
3873 while((errorcode
=readcachebuffer(returnedcb
,blckno
))==0) {
3874 bh
=(*returnedcb
)->data
;
3875 if(type
!=0 && bh
->id
!=type
) {
3877 outputcachebuffer(*returnedcb
);
3878 emptycachebuffer(*returnedcb
);
3881 if(request(PROGRAMNAME
" request","%s\n"\
3882 "has a blockid error in block %ld.\n"\
3883 "Expected was blockid 0x%08lx,\n"\
3884 "but the block says it is blockid 0x%08lx.",
3885 "Reread|Cancel",AROS_BSTR_ADDR(globals
->devnode
->dn_Name
),blckno
,type
,bh
->id
)<=0) {
3886 return(INTERR_BLOCK_WRONG_TYPE
);
3890 /* if(request(PROGRAMNAME " request","%s\n"\
3891 "is not a DOS disk.",
3892 "Retry|Cancel",AROS_BSTR_ADDR(devnode->dn_Name),blckno,type,bh->id)<=0) {
3893 return(INTERR_BLOCK_WRONG_TYPE);
3896 return(INTERR_BLOCK_WRONG_TYPE
);
3900 if(checkchecksum(*returnedcb
)==DOSFALSE
) {
3902 outputcachebuffer(*returnedcb
);
3903 emptycachebuffer(*returnedcb
);
3905 if(request(PROGRAMNAME
" request","%s\n"\
3906 "has a checksum error in block %ld.",
3907 "Reread|Cancel",AROS_BSTR_ADDR(globals
->devnode
->dn_Name
),blckno
)<=0) {
3908 return(INTERR_CHECKSUM_FAILURE
);
3912 if(BE2L(bh
->be_ownblock
)!=blckno
) {
3914 outputcachebuffer(*returnedcb
);
3915 emptycachebuffer(*returnedcb
);
3917 if(request(PROGRAMNAME
" request","%s\n"\
3918 "has a block error in block %ld.\n"\
3919 "Expected was block %ld,\n"\
3920 "but the block says it is block %ld.",
3921 "Reread|Cancel",AROS_BSTR_ADDR(globals
->devnode
->dn_Name
),blckno
,blckno
,BE2L(bh
->be_ownblock
))<=0) {
3922 return(INTERR_OWNBLOCK_WRONG
);
3933 /* How the CacheBuffers work:
3934 ==========================
3936 When the filesystem starts, the number of buffers indicated
3937 by the Mountlist are allocated. If the number of buffers
3938 is below the minimum then the filesystem will increase the
3939 number of buffers to the minimum. AddBuffers can be used
3940 later to change the number of CacheBuffers.
3942 Each CacheBuffer is linked into two chains. An LRU chain,
3943 to quickly determine the least recently used CacheBuffer,
3944 and a Hash chain. The Hash chain is used to quickly locate
3945 a CacheBuffer which contains a specific block. Empty
3946 cachebuffers are not linked in the Hash chain and have a
3949 After having read a few blocks there comes a time when you
3950 want to modify them. The CacheBuffer systems helps to make
3951 it simple to do safe updates to blocks without ever running
3952 the risk of leaving the disk in a state where links or
3953 pointers are not yet valid. If you want to modify a block
3954 or series of blocks you need to tell this to the caching
3955 system by calling newtransaction(). An operation is a series
3956 of modifications which, when written to disk completely,
3957 would result in a valid disk. By calling newtransaction() you
3958 signal that you are about to start a series of modifications
3959 which together will again result in a valid disk.
3961 If however at any point during an operation somekind of
3962 error occurs which prevents you from finishing the operation
3963 you should call deletetransaction(). This will remove all
3964 changes you made from the point when you called
3965 newtransaction() from the cache. These blocks will now never
3966 get written to disk, so there is no chance that the disk
3967 becomes invalid by partial modifications.
3969 This sums up how the caching mechanism works. The internal
3970 workings of routines like newtransaction() and
3971 deletetransaction() will be explained later on. One very
3972 important routine hasn't been mentioned here:
3973 flushtransaction(). This is the routine which actually makes
3974 modifications to the disk. It does this by flushing one
3975 operation at a time to disk (in old to new order of course)
3976 in such a way that even if the machine crashed in the middle
3977 of the flush that the disk would remain valid. After
3978 flushing all operations the cache is cleaned up.
3985 /* Creating and moving objects
3987 1. Changing the comment on an object
3988 2. Changing the name of an object
3989 3. Creating a new object
3990 (4. Moving an object)
3992 Each of these three operations involves one or more of the following:
3994 1,2,3,4 - Locating enough new room for the object
3995 1,2,3,4 - Making sure the object-node points to the new block the
3996 object is located in.
3997 2 & 3 - Hashing the object
3998 3 - Allocating an ObjectNode.
4002 'Allocating an ObjectNode' always precedes 'Hashing the Object' and 'Fixing the objectnode pointer'.
4003 'FindObjectSpace' always precedes 'Fixing the objectnode pointer'.
4005 1. FindObjectSpace OR Allocating an ObjectNode
4006 2. Fixing the objectnode pointer OR Hashing the Object */
4010 void fixlocks(struct GlobalHandle
*gh
,ULONG lastextentkey
,ULONG lastextentoffset
,ULONG filelength
) {
4011 struct ExtFileLock
*lock
=globals
->locklist
;
4017 lock
->extentoffset
=0;
4020 else if(lock
->offset
>filelength
) {
4021 /* Hmmm, this lock is positioned beyond the EOF... */
4023 if(lock
->offset
-lock
->extentoffset
>= filelength
) {
4024 lock
->extentoffset
=filelength
-(lock
->offset
-lock
->extentoffset
);
4027 lock
->extentoffset
=filelength
-lastextentoffset
;
4028 lock
->curextent
=lastextentkey
;
4030 lock
->offset
=filelength
;
4039 static LONG
extendblocksinfile(struct ExtFileLock
*lock
, ULONG blocks
) {
4040 BLCK lastextentbnode
;
4043 /* This function extends the file identified by the lock with a number
4044 of blocks. Only new Extents will be created -- the size of the file
4045 will not be altered, and changing it is left up to the caller. If
4046 the file did not have any blocks yet, then lock->curextent will be
4047 set to the first (new) ExtentBNode. It's left up up to the caller
4048 to reflect this change in object.file.data.
4050 This function must be called from within a transaction. */
4052 _XDEBUG((DEBUG_IO
,"extendblocksinfile: Increasing number of blocks by %ld. lock->curextent = %ld\n",blocks
,lock
->curextent
));
4054 if((errorcode
=seektocurrent(lock
))==0) {
4056 if((lastextentbnode
=lock
->curextent
)!=0) {
4057 struct CacheBuffer
*cb
;
4058 struct fsExtentBNode
*ebn
;
4060 while((errorcode
=findextentbnode(lastextentbnode
,&cb
,&ebn
))==0 && BE2L(ebn
->be_next
)!=0) {
4061 lastextentbnode
=BE2L(ebn
->be_next
);
4066 struct GlobalHandle
*gh
=lock
->gh
;
4068 /* We found the last Extent. Now we should see if we can extend it
4069 or if we need to add a new one and attach it to this one. */
4072 struct Space
*sl
=globals
->spacelist
;
4075 if(lastextentbnode
!=0) {
4076 struct CacheBuffer
*cb
;
4077 struct fsExtentBNode
*ebn
;
4079 if((errorcode
=findextentbnode(lastextentbnode
,&cb
,&ebn
))!=0) {
4082 searchstart
=BE2L(ebn
->be_key
)+BE2W(ebn
->be_blocks
);
4085 searchstart
=globals
->block_rovingblockptr
;
4088 if((errorcode
=smartfindandmarkspace(searchstart
,blocks
))!=0) { /* only within transaction! */
4089 _DEBUG(("extendblocksinfile: sfams returned errorcode %ld\n", errorcode
));
4093 _XDEBUG((DEBUG_IO
,"extendblocksinfile: Found some space! blocks = %ld\n",blocks
));
4095 while(blocks
!=0 && sl
->block
!=0) {
4096 BLCK newspace
=sl
->block
;
4097 ULONG newspaceblocks
;
4099 newspaceblocks
=sl
->blocks
> blocks
? blocks
: sl
->blocks
;
4101 while(newspaceblocks
!=0) {
4104 extentblocks
=newspaceblocks
> 8192 ? 8192 : newspaceblocks
;
4106 newspaceblocks
-=extentblocks
;
4108 _XDEBUG((DEBUG_IO
,"extendblocksinfile: sl->block = %ld, lastextentbnode = %ld, extentblocks = %ld\n",sl
->block
,lastextentbnode
,extentblocks
));
4110 if((errorcode
=addblocks(extentblocks
, newspace
, gh
->objectnode
, &lastextentbnode
))!=0) {
4111 _DEBUG(("extendblocksinfile: addblocks returned errorcode %ld\n", errorcode
));
4115 if(lock
->curextent
==0) {
4116 lock
->curextent
=lastextentbnode
;
4119 lock
->lastextendedblock
=newspace
+ extentblocks
;
4121 _XDEBUG((DEBUG_IO
,"extendblocksinfile: Done adding or extending an extent -- blocks = %ld, extentblocks = %ld\n",blocks
,extentblocks
));
4123 blocks
-=extentblocks
;
4124 newspace
+=extentblocks
;
4137 LONG
truncateblocksinfile(struct ExtFileLock
*lock
,ULONG blocks
,ULONG
*lastextentkey
,ULONG
*lastextentoffset
) {
4138 struct CacheBuffer
*cb
;
4139 struct fsExtentBNode
*ebn
;
4144 /* Truncates the specified file to /blocks/ blocks. This function does not
4145 take care of setting the filesize. It also doesn't check for any locks
4146 which have a fileptr which is beyond the end of the file after calling
4147 this function. Its sole purpose is to reduce the number of blocks in
4150 offset
=blocks
<<globals
->shifts_block
;
4152 _DEBUG(("truncateblocksinfile: truncating file by %ld blocks\n",blocks
));
4154 if((errorcode
=seekextent(lock
,offset
,&cb
,&ebn
,&extentoffset
))==0) {
4156 _DEBUG(("truncateblocksinfile: offset = %ld, extentoffset = %ld\n",offset
,extentoffset
));
4158 if(offset
-extentoffset
==0) {
4159 ULONG prevkey
=BE2L(ebn
->be_prev
);
4161 _DEBUG(("truncateblocksinfile: prevkey = %ld\n",prevkey
));
4163 /* Darn. This Extent needs to be killed completely, meaning that we
4164 have to set the Next pointer of the previous Extent to zero. */
4166 deleteextents(BE2L(ebn
->be_key
));
4168 if((prevkey
& 0x80000000)==0) {
4169 if((errorcode
=findextentbnode(prevkey
,&cb
,&ebn
))==0) {
4170 preparecachebuffer(cb
);
4174 errorcode
=storecachebuffer(cb
);
4176 *lastextentkey
=prevkey
;
4177 *lastextentoffset
=extentoffset
-(BE2W(ebn
->be_blocks
)<<globals
->shifts_block
);
4183 if((errorcode
=readobject((prevkey
& 0x7fffffff), &cb
, &o
))==0) {
4184 preparecachebuffer(cb
);
4186 _DEBUG(("truncateblocksinfile: cb->blckno = %ld\n",cb
->blckno
));
4188 o
->object
.file
.be_data
=0;
4191 errorcode
=storecachebuffer(cb
);
4194 *lastextentoffset
=0;
4199 ULONG newblocks
=blocks
-(extentoffset
>>globals
->shifts_block
);
4201 *lastextentkey
=BE2L(ebn
->be_key
);
4202 *lastextentoffset
=extentoffset
;
4204 _DEBUG(("truncateblocksinfile: newblocks = %ld, ebn->blocks = %ld\n",newblocks
,BE2W(ebn
->be_blocks
)));
4206 if(newblocks
!=BE2W(ebn
->be_blocks
)) {
4207 /* There is only one case where newblocks could equal en->blocks here,
4208 and that is if we tried to truncate the file to the same number of
4209 blocks the file already had! */
4211 lockcachebuffer(cb
);
4213 if((errorcode
=freespace(BE2L(ebn
->be_key
)+newblocks
,BE2W(ebn
->be_blocks
)-newblocks
))==0) {
4214 BLCK next
=BE2L(ebn
->be_next
);
4216 preparecachebuffer(cb
);
4218 ebn
->be_blocks
=W2BE(newblocks
);
4221 if((errorcode
=storecachebuffer(cb
))==0) {
4222 errorcode
=deleteextents(next
); // Careful, deleting BNode's may change the location of other BNode's as well!
4226 unlockcachebuffer(cb
);
4236 LONG
setfilesize(struct ExtFileLock
*lock
, ULONG bytes
) {
4237 struct GlobalHandle
*gh
=lock
->gh
;
4240 /* This function sets the filesize of a file to /bytes/ bytes. If the
4241 file is not yet long enough, additional blocks are allocated and
4242 added to the file. If the file is too long the file will be shortened
4243 and the lost blocks are freed.
4245 Any filehandles using this file are set to the EOF if their current
4246 position would be beyond the new EOF when truncating the file.
4248 In any other case the position of the file ptr is not altered. */
4250 _DEBUG(("setfilesize: gh = 0x%08lx. Setting to %ld bytes. Current size is %ld bytes.\n",gh
,bytes
,gh
->size
));
4252 if(bytes
!=gh
->size
) {
4256 curblocks
=(gh
->size
+globals
->bytes_block
-1)>>globals
->shifts_block
;
4257 blocksdiff
=((bytes
+globals
->bytes_block
-1)>>globals
->shifts_block
) - curblocks
;
4259 _DEBUG(("setfilesize: blocksdiff = %ld\n",blocksdiff
));
4265 if((errorcode
=extendblocksinfile(lock
, blocksdiff
))==0) {
4266 struct CacheBuffer
*cb
;
4269 /* File (now) has right amount of blocks, only exact size in bytes may differ */
4271 if((errorcode
=readobject(gh
->objectnode
, &cb
, &o
))==0) {
4272 preparecachebuffer(cb
);
4274 o
->object
.file
.be_size
=L2BE(bytes
);
4275 if(o
->object
.file
.be_data
==0) {
4276 o
->object
.file
.be_data
=L2BE(lock
->curextent
);
4279 errorcode
=storecachebuffer(cb
);
4287 gh
->data
=lock
->curextent
;
4291 deletetransaction();
4295 ULONG lastextentkey
=0;
4296 ULONG lastextentoffset
=0;
4301 /* File needs to be shortened by -/blocksdiff/ blocks. */
4303 _DEBUG(("setfilesize: Decreasing number of blocks\n"));
4305 errorcode
=truncateblocksinfile(lock
,curblocks
+blocksdiff
,&lastextentkey
,&lastextentoffset
);
4308 _DEBUG(("setfilesize: lastextentkey = %ld, lastextentoffset = %ld\n",lastextentkey
,lastextentoffset
));
4311 struct CacheBuffer
*cb
;
4314 /* File (now) has right amount of blocks, only exact size in bytes may differ */
4316 if((errorcode
=readobject(gh
->objectnode
,&cb
,&o
))==0) {
4317 preparecachebuffer(cb
);
4319 _DEBUG(("setfilesize: gh->objectnode = %ld, cb->blcno = %ld\n",gh
->objectnode
,cb
->blckno
));
4321 o
->object
.file
.be_size
=L2BE(bytes
);
4323 errorcode
=storecachebuffer(cb
);
4331 fixlocks(gh
,lastextentkey
,lastextentoffset
,bytes
);
4334 deletetransaction();
4339 lock
->bits
|=EFL_MODIFIED
;
4348 void seekforward(struct ExtFileLock
*lock
, UWORD ebn_blocks
, BLCK ebn_next
, ULONG bytestoseek
) {
4350 /* This function does a simple forward seek. It assumes /bytestoseek/ is
4351 only large enough to skip within the current extent or to the very
4352 beginning of the next extent. */
4354 lock
->offset
+=bytestoseek
;
4355 lock
->extentoffset
+=bytestoseek
;
4356 if(lock
->extentoffset
>= ebn_blocks
<<globals
->shifts_block
&& ebn_next
!=0) {
4357 lock
->extentoffset
=0;
4358 lock
->curextent
=ebn_next
;
4364 LONG
seektocurrent(struct ExtFileLock
*lock
) {
4367 /* This function checks if the currentextent is still valid. If not,
4368 it will attempt to locate the currentextent. */
4370 if(lock
->curextent
==0) {
4372 /* lock->curextent==0 can indicate 2 things:
4374 - A previously empty file was extended by another handle; in this
4375 case the file-ptr (lock->offset) of this handle is still zero.
4377 - The extent has been moved by the defragmenter, and will have to
4378 be re-located. In this case the file-ptr doesn't have to be
4381 if(lock
->offset
==0) {
4382 lock
->curextent
=lock
->gh
->data
;
4385 struct CacheBuffer
*cb
;
4386 struct fsExtentBNode
*ebn
;
4389 if((errorcode
=seekextent(lock
, lock
->offset
, &cb
, &ebn
, &extentoffset
))==0) {
4390 lock
->curextent
=BE2L(ebn
->be_key
);
4391 lock
->extentoffset
=lock
->offset
- extentoffset
;
4400 static LONG
seek(struct ExtFileLock
*lock
,ULONG offset
) {
4401 struct CacheBuffer
*cb
;
4402 struct fsExtentBNode
*ebn
;
4406 /* This function moves the file-ptr to the specified absolute file
4407 position. It will return an error if you try to seek beyond the
4410 _XDEBUG((DEBUG_SEEK
,"seek: Attempting to seek to %ld\n",offset
));
4412 if((errorcode
=seekextent(lock
,offset
,&cb
,&ebn
,&extentoffset
))==0) {
4413 lock
->curextent
=BE2L(ebn
->be_key
);
4414 lock
->extentoffset
=offset
-extentoffset
;
4415 lock
->offset
=offset
;
4417 _XDEBUG((DEBUG_SEEK
,"seek: lock->curextent = %ld, lock->extentoffset = %ld, lock->offset = %ld\n",lock
->curextent
,lock
->extentoffset
,lock
->offset
));
4420 _XDEBUG((DEBUG_SEEK
,"seek: Exiting with errorcode %ld\n",errorcode
));
4427 LONG
deleteextents(ULONG key
) {
4428 struct CacheBuffer
*cb
;
4429 struct fsExtentBNode
*ebn
;
4432 /* Deletes an fsExtentBNode structure by key and any fsExtentBNodes linked to it.
4433 This function DOES NOT fix the next pointer in a possible fsExtentBNode which
4434 might have been pointing to the first BNode we are deleting. Make sure you check
4435 this yourself, if needed.
4437 If key is zero, than this function does nothing.
4439 newtransaction() should have been called prior to calling this function. */
4441 _XDEBUG((DEBUG_NODES
,"deleteextents: Entry -- deleting extents from key %ld\n",key
));
4444 while(key
!=0 && (errorcode
=findbnode(globals
->block_extentbnoderoot
,key
,&cb
,(struct BNode
**)&ebn
))==0) {
4445 /* node to be deleted located. */
4447 // _XDEBUG((DDEBUG_NODES,"deleteextents: Now deleting key %ld. Next key is %ld\n",key,ebn->next));
4449 key
=BE2L(ebn
->be_next
);
4451 lockcachebuffer(cb
); /* Makes sure freespace() doesn't reuse this cachebuffer */
4453 if((errorcode
=freespace(BE2L(ebn
->be_key
), BE2W(ebn
->be_blocks
)))==0) {
4454 unlockcachebuffer(cb
);
4456 // _XDEBUG((DDEBUG_NODES,"deleteextents: deletebnode from root %ld, with key %ld\n",block_extentbnoderoot,ebn->key));
4458 if((errorcode
=deletebnode(globals
->block_extentbnoderoot
,BE2L(ebn
->be_key
)))!=0) { /*** Maybe use deleteinternalnode here??? */
4463 unlockcachebuffer(cb
);
4468 // _XDEBUG((DEBUG_NODES,"deleteextents: Exiting with errorcode %ld\n",errorcode));
4475 static LONG
findextentbnode(ULONG key
,struct CacheBuffer
**returned_cb
,struct fsExtentBNode
**returned_bnode
) {
4478 errorcode
=findbnode(globals
->block_extentbnoderoot
,key
,returned_cb
,(struct BNode
**)returned_bnode
);
4480 #ifdef CHECKCODE_BNODES
4481 if(*returned_bnode
==0 || BE2L((*returned_bnode
)->be_key
)!=key
) {
4482 dreq("findextentbnode: findbnode() can't find key %ld!",key
);
4483 outputcachebuffer(*returned_cb
);
4484 return(INTERR_BTREE
);
4493 LONG findobjectnode(NODE nodeno,struct CacheBuffer **returned_cb,struct fsObjectNode **returned_node) {
4494 return(findnode(block_objectnoderoot, sizeof(struct fsObjectNode), nodeno, returned_cb, (struct fsNode **)returned_node));
4499 static inline LONG
createextentbnode(ULONG key
,struct CacheBuffer
**returned_cb
,struct fsExtentBNode
**returned_bnode
) {
4500 return(createbnode(globals
->block_extentbnoderoot
,key
,returned_cb
,(struct BNode
**)returned_bnode
));
4505 LONG
seekextent(struct ExtFileLock
*lock
, ULONG offset
, struct CacheBuffer
**returned_cb
, struct fsExtentBNode
**returned_ebn
, ULONG
*returned_extentoffset
) {
4509 /* When seeking there are 2 options; we start from the current extent,
4510 or we start from the first extent. Below we determine the best
4513 if(offset
>lock
->gh
->size
) {
4514 _XDEBUG((DEBUG_SEEK
,"seekextent: Attempting to seek beyond file\n"));
4516 return(ERROR_SEEK_ERROR
);
4519 // _DEBUG(("seekextent: offset = %ld, lock->offset = %ld, lock->extentoffset = %ld, lock->curextent = %ld\n",offset, lock->offset, lock->extentoffset, lock->curextent));
4521 if(lock
->curextent
!=0 && offset
>= lock
->offset
- lock
->extentoffset
) {
4522 extentbnode
=lock
->curextent
;
4523 *returned_extentoffset
=lock
->offset
- lock
->extentoffset
;
4526 extentbnode
=lock
->gh
->data
;
4527 *returned_extentoffset
=0;
4530 /* Starting point has been determined. Let the seeking begin!
4531 We keep getting the next extent, until we find the extent which
4532 contains the required offset. */
4534 if(extentbnode
!=0) {
4535 while((errorcode
=findextentbnode(extentbnode
,returned_cb
,returned_ebn
))==0) {
4536 ULONG endbyte
=*returned_extentoffset
+(BE2W((*returned_ebn
)->be_blocks
)<<globals
->shifts_block
);
4538 if(offset
>=*returned_extentoffset
&& offset
<endbyte
) {
4539 /* Hooray! We found the correct extent. */
4543 if(BE2L((*returned_ebn
)->be_next
)==0) {
4544 /* This break is here in case we run into the end of the file.
4545 This prevents *returned_extentoffset and extentbnode
4546 from being destroyed in the lines below, since it is still
4547 valid to seek to the EOF */
4549 if(offset
>endbyte
) {
4550 /* There where no more blocks, but there should have been... */
4551 errorcode
=ERROR_SEEK_ERROR
;
4556 *returned_extentoffset
+=BE2W((*returned_ebn
)->be_blocks
)<<globals
->shifts_block
;
4557 extentbnode
=BE2L((*returned_ebn
)->be_next
);
4566 /* Notify support functions. */
4568 UBYTE
*fullpath(struct CacheBuffer
*cbstart
,struct fsObject
*o
) {
4569 struct fsObjectContainer
*oc
=cbstart
->data
;
4570 struct CacheBuffer
*cb
=cbstart
;
4571 UBYTE
*path
=&globals
->pathstring
[519];
4574 /* Returns the full path of an object, or 0 if it fails. */
4576 lockcachebuffer(cbstart
);
4580 while(oc
->be_parent
!=0) { /* Checking parent here means name in ROOT will be ignored. */
4585 while(name
!=o
->name
) {
4586 *--path
=upperchar(*--name
);
4589 if(readobject(BE2L(oc
->be_parent
),&cb
,&o
)!=0) {
4596 if(oc
->be_parent
!=0) {
4601 unlockcachebuffer(cbstart
);
4608 void checknotifyforpath(UBYTE
*path
,UBYTE notifyparent
) {
4609 struct NotifyRequest
*nr
;
4613 /* /path/ doesn't have a trailing slash and start with a root directory (no colon) */
4624 nr
=globals
->notifyrequests
;
4626 // _DEBUG(("checknotify: path = '%s'\n", path));
4631 s2
=stripcolon(nr
->nr_FullName
);
4633 while(*s1
!=0 && *s2
!=0 && *s1
==upperchar(*s2
)) {
4634 s1
++; // If last character doesn't match, this increment won't take place.
4638 /* "" == "hallo" -> no match
4641 "/shit" == "" -> match (parent dir)
4642 "shit" == "" -> match (parent dir) */
4644 // _DEBUG(("checknotify: fullpath = '%s', nr->FullName = '%s'\n",s1,s2));
4646 if( (s1
[0]==0 && (s2
[0]==0 || (s2
[0]=='/' && s2
[1]==0))) || ((s2
[0]==0 && (s1
==lastslash
|| s1
==lastslash
+1)) && notifyparent
==TRUE
) ) {
4647 /* Wow, the string in the NotifyRequest matches! We need to notify someone! */
4649 _DEBUG(("checknotify: Notificating!! nr->FullName = %s, UserData = 0x%08lx\n",nr
->nr_FullName
, nr
->nr_UserData
));
4653 /* No else, if neither flag is set then do nothing. */
4656 nr
= (struct NotifyRequest
*)nr
->nr_Next
;
4662 void checknotifyforobject(struct CacheBuffer
*cb
,struct fsObject
*o
,UBYTE notifyparent
) {
4663 checknotifyforpath(fullpath(cb
,o
),notifyparent
);
4668 void notify(struct NotifyRequest
*nr
) {
4670 /* This function sends a Notify to the client indicated by the passed
4671 in notifyrequest structure. */
4673 if((nr
->nr_Flags
& NRF_SEND_SIGNAL
)!=0) {
4674 /* Sending them a signal. */
4676 _DEBUG(("notify: Sending signal\n"));
4678 Signal(nr
->nr_stuff
.nr_Signal
.nr_Task
,1<<nr
->nr_stuff
.nr_Signal
.nr_SignalNum
);
4680 else if((nr
->nr_Flags
& NRF_SEND_MESSAGE
)!=0) {
4681 struct NotifyMessage
*nm
;
4683 /* Sending them a message. */
4685 _DEBUG(("notify: Sending message\n"));
4687 if((nm
=AllocMem(sizeof(struct NotifyMessage
),MEMF_CLEAR
))!=0) {
4688 nm
->nm_ExecMessage
.mn_ReplyPort
=globals
->msgportnotify
;
4689 nm
->nm_ExecMessage
.mn_Length
=sizeof(struct NotifyMessage
);
4691 nm
->nm_Class
=NOTIFY_CLASS
;
4692 nm
->nm_Code
=NOTIFY_CODE
;
4693 nm
->nm_NReq
=(struct NotifyRequest
*)nr
;
4695 _DEBUG(("notify: PutMsg() - UserData = 0x%08lx\n", nr
->nr_UserData
));
4697 PutMsg(nr
->nr_stuff
.nr_Msg
.nr_Port
,(struct Message
*)nm
);
4708 LONG
writedata(ULONG newbytes
, ULONG extentblocks
, BLCK newspace
, UBYTE
*data
) {
4709 ULONG blocks
=newbytes
>>shifts_block
;
4712 if(blocks
>extentblocks
) {
4713 blocks
=extentblocks
;
4716 if(blocks
!=0 && (errorcode
=write(newspace
,data
,blocks
))!=0) {
4720 if(blocks
<extentblocks
) {
4721 struct CacheBuffer
*cb
;
4723 _XDEBUG((DEBUG_IO
," writedata: blocks = %ld, newbytes = %ld\n",blocks
,newbytes
));
4725 newbytes
-=blocks
<<shifts_block
;
4726 data
+=blocks
<<shifts_block
;
4728 if((cb
=newcachebuffer(newspace
+blocks
))!=0) {
4729 unlockcachebuffer(cb
);
4731 CopyMem(data
,cb
->data
,newbytes
);
4733 errorcode
=writecachebuffer(cb
);
4734 /* At this point we can do 2 things with this cachebuffer. We can leave it
4735 hashed so if the user requests part of this block again it can quickly be grabbed
4736 from this CacheBuffer. The other option is the call emptycachebuffer()
4737 and let this buffer be reused ASAP. */
4739 emptycachebuffer(cb
);
4742 errorcode
=ERROR_NO_FREE_STORE
;
4757 static LONG
addblocks(UWORD blocks
, BLCK newspace
, NODE objectnode
, BLCK
*io_lastextentbnode
) {
4758 struct CacheBuffer
*cb
;
4759 struct fsExtentBNode
*ebn
;
4762 /* This function adds /blocks/ blocks starting at block /newspace/ to a file
4763 identified by /objectnode/ and /lastextentbnode/. /io_lastextentbnode/ can
4764 be zero if there is no ExtentBNode chain attached to this file yet.
4766 This function must be called from within a transaction.
4768 /blocks/ ranges from 1 to 8192. To be able to extend Extents which are
4769 almost full, it is wise to make this value no higher than 8192 blocks.
4771 /io_lastextentbnode/ will contain the new lastextentbnode value when this
4774 This function makes no attempt to update any locks associated with this file,
4775 nor does it update the filesize information in a possible globalhandle.
4777 If there was no chain yet, then this function will create a new one. However
4778 it will NOT update object.file.data -- this is left up to the caller. */
4780 if(*io_lastextentbnode
!=0) {
4781 /* There was already a ExtentBNode chain for this file. Extending it. */
4783 _XDEBUG((DEBUG_IO
," addblocks: Extending existing ExtentBNode chain.\n"));
4785 if((errorcode
=findextentbnode(*io_lastextentbnode
,&cb
,&ebn
))==0) {
4787 preparecachebuffer(cb
);
4789 if(BE2L(ebn
->be_key
)+BE2W(ebn
->be_blocks
)==newspace
&& BE2W(ebn
->be_blocks
)+blocks
<65536) {
4790 /* It is possible to extent the last ExtentBNode! */
4792 _XDEBUG((DEBUG_IO
," addblocks: Extending last ExtentBNode.\n"));
4794 ebn
->be_blocks
=W2BE(BE2W(ebn
->be_blocks
)+blocks
);
4796 errorcode
=storecachebuffer(cb
);
4799 /* It isn't possible to extent the last ExtentBNode so we create
4800 a new one and link it to the last ExtentBNode. */
4802 ebn
->be_next
=L2BE(newspace
);
4804 if((errorcode
=storecachebuffer(cb
))==0 && (errorcode
=createextentbnode(newspace
,&cb
,&ebn
))==0) {
4806 _XDEBUG((DEBUG_IO
," addblocks: Created new ExtentBNode.\n"));
4808 ebn
->be_key
=L2BE(newspace
);
4809 ebn
->be_prev
=L2BE(*io_lastextentbnode
);
4811 ebn
->be_blocks
=W2BE(blocks
);
4813 *io_lastextentbnode
=newspace
;
4815 if((errorcode
=storecachebuffer(cb
))==0) {
4816 globals
->block_rovingblockptr
=newspace
+blocks
;
4817 if((blocks
<<globals
->shifts_block
) <= ROVING_SMALL_WRITE
) {
4818 globals
->block_rovingblockptr
+=ROVING_RESERVED_SPACE
>>globals
->shifts_block
;
4821 if(globals
->block_rovingblockptr
>=globals
->blocks_total
) {
4822 globals
->block_rovingblockptr
=0;
4830 /* There is no ExtentBNode chain yet for this file. Attaching one! */
4832 if((errorcode
=createextentbnode(newspace
,&cb
,&ebn
))==0) {
4834 _XDEBUG((DEBUG_IO
," addblocks: Created new ExtentBNode chain.\n"));
4836 ebn
->be_key
=L2BE(newspace
);
4837 ebn
->be_prev
=L2BE(objectnode
+0x80000000);
4839 ebn
->be_blocks
=W2BE(blocks
);
4841 *io_lastextentbnode
=newspace
;
4843 if((errorcode
=storecachebuffer(cb
))==0) {
4844 globals
->block_rovingblockptr
=newspace
+blocks
;
4845 if((blocks
<<globals
->shifts_block
) <= ROVING_SMALL_WRITE
) {
4846 globals
->block_rovingblockptr
+=ROVING_RESERVED_SPACE
>>globals
->shifts_block
;
4849 if(globals
->block_rovingblockptr
>=globals
->blocks_total
) {
4850 globals
->block_rovingblockptr
=0;
4861 static void diskchangenotify(ULONG
class) {
4862 struct IOStdReq
*inputreq
;
4863 struct MsgPort
*inputport
;
4864 struct InputEvent ie
;
4867 if((inputport
=CreateMsgPort())!=0) {
4868 if((inputreq
=(struct IOStdReq
*)CreateIORequest(inputport
,sizeof(struct IOStdReq
)))!=0) {
4869 if(OpenDevice("input.device",0,(struct IORequest
*)inputreq
,0)==0) {
4877 ie
.ie_Qualifier
=IEQUALIFIER_MULTIBROADCAST
;
4878 ie
.ie_EventAddress
=0;
4881 inputreq
->io_Command
= IND_WRITEEVENT
;
4882 inputreq
->io_Length
= sizeof(struct InputEvent
);
4883 inputreq
->io_Data
= &ie
;
4885 DoIO((struct IORequest
*)inputreq
);
4887 CloseDevice((struct IORequest
*)inputreq
);
4889 DeleteIORequest(inputreq
);
4891 DeleteMsgPort(inputport
);
4900 struct ExtFileLock
*lock
;
4905 if((lock
->bits
& EFL_MODIFIED
)!=0) {
4906 /* File belonging to this lock was modified. */
4908 if(lock
->gh
!=0 && lock
->curextent
!=0) {
4909 BLCK lastblock
=lock
->curextent
;
4911 lastblock
+=lock
->extentoffset
>>shifts_block
;
4913 /* lastblock is now possibly the last block which is used by the file. This
4914 should always be true for newly created files which are being extended. */
4927 BOOL
freeupspace(void) {
4928 BOOL spacefreed
=FALSE
;
4930 /* This function tries to free up space. It does this by
4931 permanently deleting deleted files (if case of a recycled)
4932 and by flushing the current transaction if there is one.
4934 If no space could be freed, then this function returns
4935 FALSE. This is the go-ahead sign to report disk full
4938 if(hastransaction()) {
4943 if(cleanupdeletedfiles()!=FALSE
) {
4952 LONG
writetofile(struct ExtFileLock
*lock
, UBYTE
*buffer
, ULONG bytestowrite
) {
4953 struct GlobalHandle
*gh
=lock
->gh
;
4956 /* This function must be called from within a transaction! */
4958 if((gh
->protection
& FIBF_WRITE
)!=0) {
4962 /* First thing we need to do is extend the file (if needed) to
4963 accomodate for all the data we are about to write. */
4965 maxbytes
=(gh
->size
+ globals
->bytes_block
-1) & ~globals
->mask_block
; // Maximum number of bytes file can hold with the current amount of blocks.
4966 newbytes
=bytestowrite
-(maxbytes
-lock
->offset
); // Number of new bytes which would end up in newly allocated blocks.
4968 if((errorcode
=seektocurrent(lock
))==0 && (newbytes
<=0 || (errorcode
=extendblocksinfile(lock
, (newbytes
+globals
->bytes_block
-1)>>globals
->shifts_block
))==0)) {
4969 struct CacheBuffer
*extent_cb
;
4970 struct fsExtentBNode
*ebn
=0;
4973 /* At this point, the file either didn't need extending, or was succesfully extended. */
4975 newfilesize
=lock
->offset
+bytestowrite
;
4977 if(newfilesize
<gh
->size
) {
4978 newfilesize
=gh
->size
;
4981 /* If the filesize will change, then we set it below */
4983 if(newfilesize
!=gh
->size
) {
4984 struct CacheBuffer
*cb
;
4987 if((errorcode
=readobject(lock
->objectnode
,&cb
,&o
))==0) {
4988 preparecachebuffer(cb
);
4990 checksum_writelong_be(cb
->data
, &o
->object
.file
.be_size
, newfilesize
);
4991 gh
->size
=newfilesize
;
4993 if(o
->object
.file
.be_data
==0) {
4994 checksum_writelong_be(cb
->data
, &o
->object
.file
.be_data
, lock
->curextent
);
4995 gh
->data
=lock
->curextent
;
4998 errorcode
=storecachebuffer_nochecksum(cb
);
5003 while(bytestowrite
!=0 && (errorcode
=findextentbnode(lock
->curextent
, &extent_cb
, &ebn
))==0) {
5005 ULONG offsetinblock
=lock
->extentoffset
& globals
->mask_block
;
5006 BLCK ebn_next
=BE2L(ebn
->be_next
);
5007 UWORD ebn_blocks
=BE2W(ebn
->be_blocks
);
5009 if(BE2W(ebn
->be_blocks
)==lock
->extentoffset
>>globals
->shifts_block
) {
5010 /* We are at the end +1 of this extent. Skip to next one. */
5012 lock
->curextent
=BE2L(ebn
->be_next
);
5013 lock
->extentoffset
=0;
5017 if(offsetinblock
!=0 || bytestowrite
<globals
->bytes_block
) {
5019 /** Partial writes to the last block of the file will cause a
5020 read of that block, even if this block didn't yet contain
5021 any valid data, because the file was just extended. This
5024 /* File-ptr is located somewhere in the middle of a block, or at the
5025 start of the block but not at the end of the file. To add data
5026 to it we'll first need to read this block. */
5028 _XDEBUG((DEBUG_IO
,"writetofile: Partially overwriting a single block of a file. ebn->key = %ld, lock->extentoffset = %ld\n",BE2L(ebn
->be_key
),lock
->extentoffset
));
5030 bytes
=globals
->bytes_block
-offsetinblock
;
5032 if(bytes
>bytestowrite
) {
5036 // if(newbytes>0 && offsetinblock==0) { /** offsetinblock check is NOT redundant. */
5037 // struct CacheBuffer *cb=getcachebuffer();
5039 // CopyMem(buffer, cb->data, bytes);
5040 // errorcode=writethrough(lock->curextent + (lock->extentoffset>>shifts_block), cb->data, 1);
5041 // emptycachebuffer(cb);
5043 // if(errorcode!=0) {
5048 if((errorcode
=writebytes(BE2L(ebn
->be_key
)+(lock
->extentoffset
>>globals
->shifts_block
), buffer
, offsetinblock
, bytes
))!=0) {
5054 bytes
=(((ULONG
)ebn_blocks
)<<globals
->shifts_block
) - lock
->extentoffset
;
5056 if(bytes
> bytestowrite
) {
5057 bytes
=bytestowrite
& ~globals
->mask_block
;
5059 /** This is a hack to speed up writes.
5061 What it does is write more bytes than there are in the buffer
5062 available (runaway writing), to avoid a seperate partial block
5063 write. It makes sure the extra data written doesn't extend
5064 into a new 4K page (assuming MMU is using 4K pages). */
5066 // #define MMU_PAGESIZE (524288)
5068 // if(((ULONG)(buffer+bytes) & ~(MMU_PAGESIZE-1))==((ULONG)(buffer+bytes+bytes_block-1) & ~(MMU_PAGESIZE-1))) {
5069 // bytes=bytestowrite;
5073 // _XDEBUG((DEBUG_IO,"writetofile: Writing multiple blocks: blockstowrite = %ld, ebn->key = %ld, lock->extentoffset = %ld, lock->offset = %ld\n",blockstowrite, ebn->key, lock->extentoffset, lock->offset));
5075 if((errorcode
=write(BE2L(ebn
->be_key
)+(lock
->extentoffset
>>globals
->shifts_block
), buffer
, (bytes
+globals
->bytes_block
-1)>>globals
->shifts_block
))!=0) {
5080 seekforward(lock
, ebn_blocks
, ebn_next
, bytes
);
5082 bytestowrite
-=bytes
;
5089 errorcode
=ERROR_WRITE_PROTECTED
;
5097 LONG
deletefileslowly(struct CacheBuffer
*cbobject
, struct fsObject
*o
) {
5098 ULONG size
=BE2L(o
->object
.file
.be_size
);
5099 ULONG key
=BE2L(o
->object
.file
.be_data
);
5102 /* cbobject & o refer to the file to be deleted (don't use this for objects
5103 other than files!). The file is deleted a piece at the time. This is
5104 because then even in low space situations files can be deleted.
5106 Note: This function deletes an object without first checking if
5107 this is allowed. Use deleteobject() instead. */
5109 _DEBUG(("deletefileslowly: Entry\n"));
5111 /* First we search for the last ExtentBNode */
5114 struct CacheBuffer
*cb
;
5115 struct fsExtentBNode
*ebn
;
5116 ULONG currentkey
=0, prevkey
=0;
5119 lockcachebuffer(cbobject
);
5121 while((errorcode
=findbnode(globals
->block_extentbnoderoot
,key
,&cb
,(struct BNode
**)&ebn
))==0) {
5122 if(BE2L(ebn
->be_next
)==0) {
5123 currentkey
=BE2L(ebn
->be_key
);
5124 prevkey
=BE2L(ebn
->be_prev
);
5125 blocks
=BE2W(ebn
->be_blocks
);
5128 key
=BE2L(ebn
->be_next
);
5131 /* Key could be zero (in theory) or contains the last ExtentBNode for this file. */
5134 while((key
& 0x80000000)==0) {
5139 lockcachebuffer(cb
); /* Makes sure freespace() doesn't reuse this cachebuffer */
5141 if((errorcode
=freespace(currentkey
, blocks
))==0) {
5142 unlockcachebuffer(cb
);
5144 if((errorcode
=deletebnode(globals
->block_extentbnoderoot
, currentkey
))==0) {
5145 if((key
& 0x80000000)==0) {
5146 if((errorcode
=findbnode(globals
->block_extentbnoderoot
, key
, &cb
, (struct BNode
**)&ebn
))==0) {
5147 preparecachebuffer(cb
);
5150 currentkey
=BE2L(ebn
->be_key
);
5151 prevkey
=BE2L(ebn
->be_prev
);
5152 blocks
=BE2W(ebn
->be_blocks
);
5154 errorcode
=storecachebuffer(cb
);
5158 preparecachebuffer(cbobject
);
5160 checksum_writelong_be(cbobject
->data
, &o
->object
.file
.be_size
, 0);
5161 checksum_writelong_be(cbobject
->data
, &o
->object
.file
.be_data
, 0);
5163 // o->object.file.data=0;
5164 // o->object.file.size=0;
5166 if((errorcode
=storecachebuffer_nochecksum(cbobject
))==0) {
5167 errorcode
=setrecycledinfodiff(0, -((size
+globals
->bytes_block
-1)>>globals
->shifts_block
));
5173 unlockcachebuffer(cb
);
5177 /* Unlocked CacheBuffers could be killed after an endtransaction()! */
5181 deletetransaction();
5187 unlockcachebuffer(cbobject
);
5190 _DEBUG(("deletefileslowly: Alternative way errorcode = %ld\n",errorcode
));
5194 /* File-data was succesfully freed. Now remove the empty object. */
5198 if((errorcode
=removeobject(cbobject
, o
))==0) {
5203 deletetransaction();
5206 _DEBUG(("deletefileslowly: Exiting with errorcode = %ld\n",errorcode
));
5218 ReadOriginalCacheBuffer
5227 The transaction system allows the filesystem to keep track
5228 of changes made to blocks in the cache. Every change is
5229 stored in a transaction buffer. The transaction buffer and
5230 the original version of a block can be used to restore the
5231 latest version of a block at any time.
5233 At any time you can use readcachebuffer() to get the latest
5234 version of a block. This could be a partially modified
5235 version if you're in the middle of a transaction, the latest
5236 version stored in the transaction buffer or the original
5239 When you want to make changes to a block you call
5240 preparecachebuffer(). This checks if the block you're
5241 preparing to change is the original version, and if so makes
5242 a backup copy. This copy is not strictly needed, but it
5243 speeds up the filesystem to keep the original version around
5244 in case we need it later. The preparecachebuffer() function
5245 also calls lockcachebuffer() so the block you're changing
5246 won't be reused in subsequent cache operations.
5248 When you're satisfied with the changes you've made to a
5249 specific block you should call storecachebuffer(). This
5250 stores the changes into the transaction buffer. From that
5251 point on readcachebuffer() will be able to recreate the
5252 block with your new modifications.
5254 Before calling preparecachebuffer() for the first time, you
5255 need to call newtransaction(). This is to let the
5256 transaction system know you're about to start a new series
5259 When you're done making all the changes to multiple blocks
5260 you need to call endtransaction(). This makes all the
5261 changes permanent. If there was an error along the way you
5262 can call deletetransaction() and all the changes you stored
5263 with storecachebuffer() since you're last call to
5264 newtransaction() will automatically be discarded.
5266 Any cachebuffers you had locked at the time which had
5267 changes in them will be restored to their original state (in
5268 reality these buffers will simply be reread using
5273 x=readcachebuffer(0); // x.data = 1
5277 preparecachebuffer(x);
5281 storecachebuffer(cb);
5283 deletetransaction(); // x.data = 1;
5285 read(x) -> "AA"; newtr(); prep(x); write("CC") -> "CC"; store(x); endtr() -> "CC";
5287 read(x) -> "AA"; newtr(); prep(x); write("CC") -> "CC"; store(x); deltr() -> "AA";
5289 read(x) -> "AA"; newtr(); prep(x); write("CC") -> "CC"; store(x); newtr(); prep(x); write("EE") -> "EE"; store(x); deltr() -> "CC"; deltr() -> "AA";
5297 LONG
setnextextent(BLCK next
, BLCK key
) {
5298 struct CacheBuffer
*cb
;
5299 struct fsExtentBNode
*ebn
;
5302 /* This function set the previous value of the
5303 passed Extent. If the passed Extent is zero
5304 then this function does nothing. */
5306 if(next
!=0 && (errorcode
=findextentbnode(next
, &cb
, &ebn
))==0) {
5307 preparecachebuffer(cb
);
5309 ebn
->be_prev
=L2BE(key
);
5311 errorcode
=storecachebuffer(cb
);
5319 LONG
setprevextent(BLCK prev
, BLCK key
) {
5320 struct CacheBuffer
*cb
;
5321 struct fsExtentBNode
*ebn
;
5324 /* This function sets the next value of the
5325 passed Extent/Object to key. */
5327 if((prev
& 0x80000000)==0 && (errorcode
=findextentbnode(prev
, &cb
, &ebn
))==0) {
5328 preparecachebuffer(cb
);
5330 ebn
->be_next
=L2BE(key
);
5332 errorcode
=storecachebuffer(cb
);
5337 if((errorcode
=readobject((prev
& 0x7fffffff), &cb
, &o
))==0) {
5338 preparecachebuffer(cb
);
5340 o
->object
.file
.be_data
=L2BE(key
);
5342 errorcode
=storecachebuffer(cb
);
5351 LONG
mergeextent(BLCK key
) {
5352 struct CacheBuffer
*cb
;
5353 struct fsExtentBNode
*ebn
;
5356 /* This function tries to merge the current extent with the
5357 next extent. If the extent can't be merged, or was
5358 succesfully merged then this function returns 0. Any
5359 error which occured during merging will be returned. */
5361 if((errorcode
=findextentbnode(key
, &cb
, &ebn
))==0) {
5363 /* We check if we found the right key, if there is a next Extent and
5364 if the two Extents touch each other: */
5366 if(BE2L(ebn
->be_key
)==key
&& BE2L(ebn
->be_next
)!=0 && BE2L(ebn
->be_key
)+BE2W(ebn
->be_blocks
) == BE2L(ebn
->be_next
)) {
5367 struct CacheBuffer
*cb2
;
5368 struct fsExtentBNode
*ebn2
;
5370 if((errorcode
=findextentbnode(BE2L(ebn
->be_next
), &cb2
, &ebn2
))==0 && BE2W(ebn2
->be_blocks
)+BE2W(ebn
->be_blocks
) < 65536) {
5371 BLCK next
=BE2L(ebn2
->be_next
);
5373 /* Merge next extent with our extent */
5375 preparecachebuffer(cb
);
5377 ebn
->be_blocks
=W2BE(BE2W(ebn
->be_blocks
)+BE2W(ebn2
->be_blocks
));
5378 ebn
->be_next
=L2BE(next
);
5380 if((errorcode
=storecachebuffer(cb
))==0) { // call storecachebuffer() here, because deletebnode() may move our BNode.
5382 if((errorcode
=deletebnode(globals
->block_extentbnoderoot
, BE2L(ebn2
->be_key
)))==0) { /*** Maybe use deleteinternalnode here??? */
5383 errorcode
=setnextextent(next
, key
);
5395 LONG
insertextent(BLCK key
, BLCK next
, BLCK prev
, ULONG blocks
) {
5396 struct CacheBuffer
*cb
=0;
5397 struct fsExtentBNode
*ebn
=0;
5400 /* This function creates a new extent, but won't create one if it can
5401 achieve the same effect by extending the next or previous extent.
5402 In the unlikely case that the new extent is located EXACTLY between
5403 its predecessor and successor then an attempt will be made to merge
5404 these 3 extents into 1. */
5407 prev available & mergeable -> merge.
5408 prev available, but not mergeable -> create new -> update next -> update previous.
5409 prev not available -> create new -> update next -> update object
5412 if((prev
& 0x80000000)!=0 || (errorcode
=findextentbnode(prev
, &cb
, &ebn
))==0) {
5414 if((prev
& 0x80000000)==0 && prev
+BE2W(ebn
->be_blocks
) == key
&& BE2W(ebn
->be_blocks
)+blocks
< 65536) {
5416 /* Extent we are inserting is mergeable with its previous extent. */
5418 preparecachebuffer(cb
);
5420 ebn
->be_blocks
=W2BE(BE2W(ebn
->be_blocks
)+blocks
); /* This merges the previous and the new extent */
5422 if((errorcode
=storecachebuffer(cb
))==0) {
5423 errorcode
=mergeextent(BE2L(ebn
->be_key
));
5428 /* Extent we are inserting couldn't be merged with its previous extent. */
5430 if((errorcode
=setprevextent(prev
, key
))==0 && (errorcode
=createextentbnode(key
, &cb
, &ebn
))==0) {
5432 /* Succesfully updated previous extent, or the object. Also created new BNode */
5434 ebn
->be_key
=L2BE(key
);
5435 ebn
->be_prev
=L2BE(prev
);
5436 ebn
->be_next
=L2BE(next
);
5437 ebn
->be_blocks
=BE2W(blocks
);
5439 if((errorcode
=storecachebuffer(cb
))==0) {
5440 if((errorcode
=setnextextent(next
, key
))==0) {
5453 LONG
truncateextent(BLCK key
, LONG blocks
) {
5454 struct CacheBuffer
*cb
;
5455 struct fsExtentBNode
*ebn
;
5458 /* Truncates the extended by the given amount of blocks.
5459 If the amount is negative then the truncation occurs
5460 at the start, otherwise at the end.
5462 This function returns INTERR_EXTENT if you tried to
5463 truncate to zero blocks (or beyond). Any errorcode
5464 is returned. If blocks is zero, then this function
5467 Mar 20 1999: The truncation at the start could cause
5468 BNode's to get lost (because they are
5469 indexed by their start block). Fixed. */
5472 if((errorcode
=findextentbnode(key
, &cb
, &ebn
))==0) {
5475 b
=blocks
<0 ? -blocks
: blocks
;
5477 if(b
<BE2W(ebn
->be_blocks
) && BE2L(ebn
->be_key
)==key
) {
5479 ULONG next
=BE2L(ebn
->be_next
);
5480 ULONG prev
=BE2L(ebn
->be_prev
);
5481 UWORD blocks
=BE2W(ebn
->be_blocks
)-b
;
5483 /* Truncating at the start. */
5485 if((errorcode
=deletebnode(globals
->block_extentbnoderoot
, key
))==0) {
5489 if((errorcode
=createbnode(globals
->block_extentbnoderoot
, key
, &cb
, (struct BNode
**)&ebn
))==0) {
5490 ebn
->be_key
=L2BE(key
);
5491 ebn
->be_next
=L2BE(next
);
5492 ebn
->be_prev
=L2BE(prev
);
5493 ebn
->be_blocks
=W2BE(blocks
);
5495 if((errorcode
=storecachebuffer(cb
))==0) {
5496 /* Truncating at start means changing the key value. This
5497 means that the next and previous BNode's must also be
5500 if((errorcode
=setnextextent(next
, key
))==0) {
5501 errorcode
=setprevextent(prev
, key
);
5509 /* Truncating at the end. */
5511 preparecachebuffer(cb
);
5513 ebn
->be_blocks
=W2BE(BE2W(ebn
->be_blocks
)-b
);
5515 errorcode
=storecachebuffer(cb
);
5519 errorcode
=INTERR_EXTENT
;
5529 static LONG
copy(BLCK source
, BLCK dest
, ULONG totblocks
, UBYTE
*optimizebuffer
) {
5533 /* Low-level function to copy blocks from one place to another. */
5535 while(totblocks
!=0) {
5537 if(blocks
> (OPTBUFSIZE
>>globals
->shifts_block
)) {
5538 blocks
=OPTBUFSIZE
>>globals
->shifts_block
;
5541 if((errorcode
=read(source
, optimizebuffer
, blocks
))!=0) {
5545 if((errorcode
=write(dest
, optimizebuffer
, blocks
))!=0) {
5559 LONG
deleteextent(struct CacheBuffer
*cb
, struct fsExtentBNode
*ebn
) {
5563 /* Deletes an fsExtentBNode structure and properly relinks the rest of the chain.
5564 No space will be given free.
5566 newtransaction() should have been called prior to calling this function. */
5568 next
=BE2L(ebn
->be_next
);
5569 prev
=BE2L(ebn
->be_prev
);
5571 if((errorcode
=deletebnode(globals
->block_extentbnoderoot
,BE2L(ebn
->be_key
)))==0) { /*** Maybe use deleteinternalnode here??? */
5572 if((errorcode
=setnextextent(next
, prev
))==0) {
5573 errorcode
=setprevextent(prev
, next
);
5582 static WORD
enough_for_add_moved(void) {
5583 if(globals
->defragmentlongs
>5) {
5589 static inline void add_moved(ULONG blocks
, ULONG from
, ULONG to
) {
5590 if(globals
->defragmentsteps
!=0) {
5591 *globals
->defragmentsteps
++=AROS_LONG2BE(MAKE_ID('M','O','V','E'));
5592 *globals
->defragmentsteps
++=3;
5593 *globals
->defragmentsteps
++=blocks
;
5594 *globals
->defragmentsteps
++=from
;
5595 *globals
->defragmentsteps
++=to
;
5596 *globals
->defragmentsteps
=0;
5598 globals
->defragmentlongs
-=5;
5602 static inline void add_done(void) {
5603 if(globals
->defragmentsteps
!=0) {
5604 *globals
->defragmentsteps
++=AROS_LONG2BE(MAKE_ID('D','O','N','E'));
5605 *globals
->defragmentsteps
++=0;
5606 *globals
->defragmentsteps
=0;
5608 globals
->defragmentlongs
-=2;
5614 LONG
moveextent(struct fsExtentBNode
*ebn
, BLCK dest
, UWORD blocks
) {
5618 /* This function (partially) moves the Extent to /dest/.
5619 /blocks/ is the number of blocks moved; if blocks is
5620 equal to the size of the Extent, then the Extent will
5621 be deleted. Else the start of the Extent will be
5624 if((buf
=AllocVec(OPTBUFSIZE
, globals
->bufmemtype
))!=0) {
5625 BLCK key
=BE2L(ebn
->be_key
);
5626 BLCK next
=BE2L(ebn
->be_next
);
5627 BLCK prev
=BE2L(ebn
->be_prev
);
5628 UWORD blocksinextent
=BE2W(ebn
->be_blocks
);
5630 if((errorcode
=copy(key
, dest
, blocks
, buf
))==0) { // This functions knows that OPTBUFSIZE is the size of the buffer!
5632 /* Data has been physically moved -- nothing has been
5633 permanently altered yet. */
5635 if((errorcode
=markspace(dest
, blocks
))==0) {
5637 if((errorcode
=freespace(key
, blocks
))==0) {
5639 /* Bitmap has been altered to reflect the new location of the
5640 moved data. Now we either need to truncate the Extent (if
5641 it was partially moved) or remove it. */
5643 if(blocksinextent
==blocks
) {
5644 struct CacheBuffer
*cb
;
5646 if((errorcode
=findextentbnode(key
, &cb
, &ebn
))==0) {
5647 errorcode
=deleteextent(cb
, ebn
);
5652 errorcode
=truncateextent(key
, -blocks
);
5656 if((errorcode
=insertextent(dest
, next
, prev
, blocks
))==0) {
5657 add_moved(blocks
, key
, dest
);
5667 errorcode
=ERROR_NO_FREE_STORE
;
5675 static LONG
fillgap(BLCK key
) {
5676 struct CacheBuffer
*cb
;
5677 struct fsExtentBNode
*ebn
;
5680 /* This function will attempt to fill the gap behind an extent with
5681 data from the next extent. This in effect merges the extent and
5682 the next extent (partially). */
5684 if((errorcode
=findextentbnode(key
, &cb
, &ebn
))==0) {
5685 ULONG next
=BE2L(ebn
->be_next
);
5687 key
+=BE2W(ebn
->be_blocks
);
5689 while(next
!=0 && (errorcode
=findextentbnode(next
, &cb
, &ebn
))==0) { // !! failed !!
5690 UWORD blocks
=BE2W(ebn
->be_blocks
);
5693 lockcachebuffer(cb
);
5695 if((free
=availablespace(key
, 1024))>0) {
5697 unlockcachebuffer(cb
);
5699 _DEBUG(("fillgap: availablespace() returned %ld\n",free
));
5701 /* The gap consists of /free/ blocks. */
5703 if(free
> blocks
&& enough_for_add_moved()!=FALSE
) {
5704 next
=BE2L(ebn
->be_next
);
5710 if((errorcode
=moveextent(ebn
, key
, MIN(free
, blocks
)))!=0) {
5717 unlockcachebuffer(cb
);
5722 _DEBUG(("fillgap: exiting with errorcode %ld\n",errorcode
));
5729 LONG
getbnode(BLCK block
, struct CacheBuffer
**returned_cb
, struct fsExtentBNode
**returned_ebn
) {
5732 /* This function gets the ExtentBNode which starts at the given
5733 block or the first one after the given block. Zero *ebn indicates
5734 there were no ExtentBNode's at or after the given block. */
5736 if((errorcode
=findbnode(globals
->block_extentbnoderoot
, block
, returned_cb
, (struct BNode
**)returned_ebn
))==0) {
5738 _DEBUG(("getbnode: ebn->key = %ld, ebn->prev = %ld, ebn->blocks = %ld\n",BE2L((*returned_ebn
)->be_key
), BE2L((*returned_ebn
)->be_prev
), BE2W((*returned_ebn
)->be_blocks
)));
5740 if(*returned_ebn
!=0 && BE2L((*returned_ebn
)->be_key
)<block
) {
5741 errorcode
=nextbnode(globals
->block_extentbnoderoot
, returned_cb
, (struct BNode
**)returned_ebn
);
5743 _DEBUG(("getbnode: 2: ebn->key = %ld, ebn->prev = %ld, ebn->blocks = %ld\n",BE2L((*returned_ebn
)->be_key
), BE2L((*returned_ebn
)->be_prev
), BE2W((*returned_ebn
)->be_blocks
)));
5753 LONG
makefreespace(BLCK block
) {
5754 struct CacheBuffer
*cb
;
5755 struct fsExtentBNode
*ebn
;
5758 /* This function tries to move the data located at /block/ to
5759 another area of the disk. */
5761 if((errorcode
=findextentbnode(block
, &cb
, &ebn
))==0) {
5766 lockcachebuffer(cb
);
5768 blocks
=MIN(OPTBUFSIZE
>>shifts_block
, ebn
->blocks
);
5770 if((errorcode
=findspace2_backwards(blocks
, block
, blocks_total
, &startblock
, &newblocks
))==0) {
5771 unlockcachebuffer(cb
);
5775 _DEBUG(("makefreespace: Looking for %ld blocks from block %ld, and found %ld blocks at block %ld.\n", blocks
, block
, newblocks
, startblock
));
5777 errorcode
=moveextent(ebn
, startblock
, newblocks
);
5780 errorcode
=ERROR_DISK_FULL
;
5784 unlockcachebuffer(cb
);
5793 LONG
makefreespace(BLCK block
) {
5794 struct CacheBuffer
*cb
;
5795 struct fsExtentBNode
*ebn
;
5799 /* This function tries to move the data located at /block/ to
5800 another area of the disk. */
5802 if((errorcode
=findextentbnode(block
, &cb
, &ebn
))==0) {
5808 lockcachebuffer(cb
);
5810 blocks
=MIN(OPTBUFSIZE
>>globals
->shifts_block
, BE2W(ebn
->be_blocks
));
5812 if((errorcode
=findspace2_backwards(blocks
, BE2L(ebn
->be_key
), globals
->blocks_total
, &startblock
, &newblocks
))==0) { // ebn->key should not be changed to block.
5813 unlockcachebuffer(cb
);
5817 _DEBUG(("makefreespace: Looking for %ld blocks from block %ld, and found %ld blocks at block %ld.\n", blocks
, block
, newblocks
, startblock
));
5819 if((errorcode
=moveextent(ebn
, startblock
, newblocks
))!=0) {
5825 errorcode
=ERROR_DISK_FULL
;
5831 unlockcachebuffer(cb
);
5839 if((errorcode
=getbnode(block
, &cb
, &ebn
))!=0 || ebn
==0) {
5843 } while((BE2L(ebn
->be_prev
) & 0x80000000)==0);
5851 LONG
skipunmoveable(BLCK block
) {
5852 struct CacheBuffer
*cb
;
5853 struct fsExtentBNode
*ebn
;
5855 /* This function looks for moveable data or free space starting
5856 from the given block. It returns -1 in case of failure, or
5857 the first moveable block it finds. If there ain't no more
5858 moveable blocks, then blocks_total is returned. */
5860 if((findbnode(globals
->block_extentbnoderoot
, block
, &cb
, (struct BNode
**)&ebn
))==0) {
5861 if(ebn
!=0 && ebn
->be_key
==L2BE(block
)) {
5862 return((LONG
)block
);
5864 else if(ebn
==0 || BE2L(ebn
->be_key
)>=block
|| nextbnode(globals
->block_extentbnoderoot
, &cb
, (struct BNode
**)&ebn
)==0) {
5866 BLCK key
=BE2L(ebn
->be_key
);
5869 /* Found something moveable, but maybe there was some free space before the
5872 if((used
=allocatedspace(block
, key
-block
))!=-1) {
5873 if(block
+used
<key
) {
5874 return((LONG
)block
+used
);
5884 if((errorcode
=findspace(1, block
, globals
->blocks_total
, &block
))==0) {
5885 return((LONG
)block
);
5887 else if(errorcode
==ERROR_DISK_FULL
) {
5888 return((LONG
)globals
->blocks_total
);
5898 struct fsExtentBNode
*startofextentbnodechain(struct fsExtentBNode
*ebn
) {
5899 struct CacheBuffer
*cb
;
5902 while((BE2L(ebn
->be_prev
) & 0x80000000)==0 && (errorcode
=findextentbnode(BE2L(ebn
->be_prev
), &cb
, &ebn
))==0) {
5915 LONG
findmatch(BLCK startblock
, ULONG blocks
, ULONG
*bestkey
) {
5916 struct CacheBuffer
*cb
;
5917 struct fsExtentBNode
*ebn
;
5918 // struct fsExtentBNode *ebn_start;
5922 /* This function looks for the start of a ExtentBNode chain
5923 which matches the given size. If none is found, then the
5924 next smaller chain is returned. If none is found, then a
5925 larger chain is returned. If there are no chains at all
5928 The first ExtentBNode examined is determined by the start
5929 block number which is passed. */
5931 _DEBUG(("findmatch: Looking for a chain of %ld blocks starting from block %ld\n", blocks
, startblock
));
5935 if((errorcode
=getbnode(startblock
, &cb
, &ebn
))==0 && ebn
!=0) {
5937 _DEBUG(("findmatch: 1, ebn->key = %ld, ebn->blocks = %ld\n", ebn
->key
, ebn
->blocks
));
5940 struct CacheBuffer
*cb2
;
5941 struct fsExtentBNode
*ebn_start
=ebn
;
5943 ULONG total
=ebn
->blocks
; /* If larger than bestblocks, then we can stop looking for the start of the ExtentBNode chain early. */
5944 ULONG key
, newblocks
;
5946 lockcachebuffer(cb
);
5947 // ebn_start=startofextentbnodechain(ebn);
5949 struct CacheBuffer
*cb
;
5951 while((total
<bestblocks
|| bestblocks
==0) && (ebn_start
->prev
& 0x80000000)==0 && ebn_start
->prev
>= ebn
->key
&& (errorcode
=findextentbnode(ebn_start
->prev
, &cb
, &ebn_start
))==0) {
5952 total
+=ebn_start
->blocks
;
5955 unlockcachebuffer(cb
);
5961 if((total
<bestblocks
|| bestblocks
==0) && (ebn_start
->prev
& 0x80000000)!=0) {
5963 _DEBUG(("findmatch: 2, ebn->key = %ld\n", ebn
->key
));
5967 lockcachebuffer(cb
);
5968 errorcode
=readobject(ebn_start
->prev
& 0x7FFFFFFF, &cb2
, &o
);
5969 unlockcachebuffer(cb
);
5975 _DEBUG(("findmatch: 3, filesize = %ld\n",o
->object
.file
.size
));
5977 newblocks
=(o
->object
.file
.size
+bytes_block
-1)>>shifts_block
;
5979 if(newblocks
==blocks
) { /* Found ideal match */
5983 else if(newblocks
<blocks
) {
5984 if(newblocks
>bestblocks
|| bestblocks
>blocks
) {
5986 bestblocks
=newblocks
;
5989 else if(bestblocks
==0 || newblocks
<bestblocks
) {
5991 bestblocks
=newblocks
;
5995 } while((errorcode
=nextbnode(block_extentbnoderoot
, &cb
, (struct BNode
**)&ebn
))==0 && ebn
!=0);
6005 void newfragmentinit_large(ULONG blocks
) {
6007 globals
->bestblocks
=0;
6008 globals
->searchedblocks
=blocks
;
6013 ULONG
newfragment_large(ULONG block
, ULONG blocks
) {
6014 if(blocks
==globals
->searchedblocks
) { /* Found ideal match */
6017 else if(blocks
<globals
->searchedblocks
) {
6018 if(blocks
>globals
->bestblocks
|| globals
->bestblocks
>globals
->searchedblocks
) {
6019 globals
->bestkey
=block
;
6020 globals
->bestblocks
=blocks
;
6023 else if(globals
->bestblocks
==0 || blocks
<globals
->bestblocks
) {
6024 globals
->bestkey
=block
;
6025 globals
->bestblocks
=blocks
;
6034 ULONG
newfragment_large(ULONG block
, ULONG blocks
, UBYTE type
) {
6036 if(blocks
==searchedblocks
) { /* Found ideal match */
6039 else if(blocks
<searchedblocks
) {
6040 if(blocks
>bestblocks
|| bestblocks
>searchedblocks
) {
6045 else if(bestblocks
==0 || blocks
<bestblocks
) {
6056 ULONG
newfragmentend_large(void) {
6057 return(globals
->bestkey
);
6063 void newfragmentinit_small(ULONG blocks
) {
6064 ULONG
*f
=globals
->fragment
;
6067 newfragmentinit_large(blocks
);
6079 void newfragmentinit_small(ULONG blocks) {
6081 UBYTE *fb=fragmenttype;
6084 newfragmentinit_large(blocks);
6094 ULONG newfragment_small(ULONG block, ULONG blocks, UBYTE type) {
6095 if(blocks<searchedblocks) {
6096 if(fragment[blocks]==0 || (fragmenttype[blocks]!=0 && type==0)) {
6097 ULONG blocks2=searchedblocks-blocks;
6099 fragment[blocks]=block;
6100 fragmenttype[blocks]=type;
6102 if(blocks2==blocks) {
6106 if(fragment[blocks2]!=0) {
6107 if(fragmenttype[blocks]==0 && fragmenttype[blocks2]==0) {
6108 return(fragment[blocks]);
6114 return(newfragment_large(block, blocks, type));
6120 ULONG
newfragment_small(ULONG block
, ULONG blocks
) {
6121 if(blocks
<globals
->searchedblocks
&& globals
->fragment
[blocks
]==0) {
6122 ULONG blocks2
=globals
->searchedblocks
-blocks
;
6124 globals
->fragment
[blocks
]=block
;
6126 if(blocks2
==blocks
) {
6130 if(globals
->fragment
[blocks2
]!=0) {
6131 return(globals
->fragment
[blocks
]);
6135 return(newfragment_large(block
, blocks
));
6140 ULONG
newfragmentend_small(void) {
6141 return(newfragmentend_large());
6148 LONG
findmatch(BLCK startblock
, ULONG blocks
, ULONG
*bestkey
) {
6149 struct CacheBuffer
*cb
;
6150 struct fsExtentBNode
*ebn
;
6151 ULONG lastextentend
=0;
6152 LONG maxscan
=defrag_maxfilestoscan
;
6155 /* This function looks for the start of a ExtentBNode chain
6156 which matches the given size. If none is found, then the
6157 next smaller chain is returned. If none is found, then a
6158 larger chain is returned. If there are no chains at all
6161 The first ExtentBNode examined is determined by the start
6162 block number which is passed. */
6164 _DEBUG(("findmatch: Looking for a chain of %ld blocks starting from block %ld\n", blocks
, startblock
));
6168 if(blocks
>FRAGMENTS
-1) {
6169 newfragmentinit_large(blocks
);
6172 newfragmentinit_small(blocks
);
6175 if((errorcode
=getbnode(startblock
, &cb
, &ebn
))==0 && ebn
!=0) {
6177 _DEBUG(("findmatch: ebn->key = %ld, ebn->blocks = %ld\n", ebn
->key
, ebn
->blocks
));
6180 if((ebn
->prev
& 0x80000000)!=0) {
6181 struct CacheBuffer
*cb2
;
6186 /* Found the start of a candidate chain. */
6188 lockcachebuffer(cb
);
6189 errorcode
=readobject(ebn
->prev
& 0x7FFFFFFF, &cb2
, &o
);
6190 unlockcachebuffer(cb
);
6196 newblocks
=(o
->object
.file
.size
+bytes_block
-1)>>shifts_block
;
6198 fragmenttype
=lastextentend
==ebn
->key
? 1 : 0;
6200 if(blocks
>FRAGMENTS
-1) {
6201 *bestkey
=newfragment_large(ebn
->key
, newblocks
, fragmenttype
);
6204 *bestkey
=newfragment_small(ebn
->key
, newblocks
, fragmenttype
);
6215 lastextentend
=ebn
->next
==0 ? ebn
->key
+ ebn
->blocks
: 0;
6217 } while((errorcode
=nextbnode(block_extentbnoderoot
, &cb
, (struct BNode
**)&ebn
))==0 && ebn
!=0);
6220 if(blocks
>FRAGMENTS
-1) {
6221 *bestkey
=newfragmentend_large();
6224 *bestkey
=newfragmentend_small();
6235 LONG
findmatch_fromend(BLCK startblock
, ULONG blocks
, ULONG
*bestkey
) {
6236 struct CacheBuffer
*cb
;
6237 struct fsExtentBNode
*ebn
;
6238 LONG maxscan
=globals
->defrag_maxfilestoscan
;
6241 /* This function looks for the start of a ExtentBNode chain
6242 which matches the given size. If none is found, then the
6243 next smaller chain is returned. If none is found, then a
6244 larger chain is returned. If there are no chains at all
6247 The first ExtentBNode examined is determined by the start
6248 block number which is passed. */
6250 _DEBUG(("findmatch_fromend: Looking for a chain of %ld blocks starting from block %ld\n", blocks
, startblock
));
6254 if(blocks
>FRAGMENTS
-1) {
6255 newfragmentinit_large(blocks
);
6258 newfragmentinit_small(blocks
);
6261 if((errorcode
=lastbnode(globals
->block_extentbnoderoot
, &cb
, (struct BNode
**)&ebn
))==0 && ebn
!=0 && BE2L(ebn
->be_key
)>=startblock
) {
6263 _DEBUG(("findmatch_fromend: ebn->key = %ld, ebn->blocks = %ld\n", BE2L(ebn
->be_key
), BE2W(ebn
->be_blocks
)));
6266 if((BE2L(ebn
->be_prev
) & 0x80000000)!=0) { // Is this a 'first fragment' of something?
6267 struct CacheBuffer
*cb2
;
6271 _DEBUG(("findmatch_fromend!: ebn->key = %ld, ebn->blocks = %ld\n", BE2L(ebn
->be_key
), BE2W(ebn
->be_blocks
)));
6273 /* Found the start of a candidate chain. */
6275 lockcachebuffer(cb
);
6276 errorcode
=readobject(BE2L(ebn
->be_prev
) & 0x7FFFFFFF, &cb2
, &o
);
6277 unlockcachebuffer(cb
);
6283 newblocks
=(BE2L(o
->object
.file
.be_size
)+globals
->bytes_block
-1)>>globals
->shifts_block
;
6285 if(blocks
>FRAGMENTS
-1) {
6286 *bestkey
=newfragment_large(BE2L(ebn
->be_key
), newblocks
);
6289 *bestkey
=newfragment_small(BE2L(ebn
->be_key
), newblocks
);
6300 } while((errorcode
=previousbnode(globals
->block_extentbnoderoot
, &cb
, (struct BNode
**)&ebn
))==0 && ebn
!=0 && BE2L(ebn
->be_key
)>=startblock
);
6303 if(blocks
>FRAGMENTS
-1) {
6304 *bestkey
=newfragmentend_large();
6307 *bestkey
=newfragmentend_small();
6311 _DEBUG(("findmatch_fromend: errorcode=%ld\n", errorcode
));
6324 if((free
=availablespace(globals
->block_defragptr
, 256))!=-1) {
6326 _DEBUG(("Defragmenter: Found %ld blocks of free space at block %ld.\n", free
, globals
->block_defragptr
));
6329 struct CacheBuffer
*cb
;
6330 struct fsExtentBNode
*ebn
;
6332 /* Determine in which extent block_defragptr is located. */
6334 if((errorcode
=findbnode(globals
->block_extentbnoderoot
, globals
->block_defragptr
, &cb
, (struct BNode
**)&ebn
))==0) {
6335 if(ebn
==0 || BE2L(ebn
->be_key
)!=globals
->block_defragptr
) {
6338 _DEBUG(("Defragmenter: Found unmoveable data at block %ld.\n", globals
->block_defragptr
));
6340 /* Skip unmoveable data */
6342 if((block
=skipunmoveable(globals
->block_defragptr
))!=-1) {
6343 globals
->block_defragptr
=block
;
6346 errorcode
=INTERR_DEFRAGMENTER
;
6349 else if((BE2L(ebn
->be_prev
) & 0x80000000)!=0 || BE2L(ebn
->be_prev
)<globals
->block_defragptr
) {
6351 _DEBUG(("Defragmenter: Found a (partially) defragmented extent at block %ld.\n", globals
->block_defragptr
));
6353 if(BE2L(ebn
->be_next
)==0 || BE2L(ebn
->be_next
) == BE2L(ebn
->be_key
)+BE2W(ebn
->be_blocks
)) {
6354 /* If there is no next Extent, or if the next Extent is touching
6355 this one, then skip the current one. */
6357 _DEBUG(("Defragmenter: Extent has no next or next is touching this one.\n"));
6359 globals
->block_defragptr
+=BE2W(ebn
->be_blocks
);
6363 BLCK key
=BE2L(ebn
->be_key
);
6364 BLCK next
=BE2L(ebn
->be_next
);
6365 UWORD blocks
=BE2W(ebn
->be_blocks
);
6367 _DEBUG(("Defragmenter: Extent has a next extent.\n"));
6369 if((freeafter
=availablespace(key
+blocks
, 256))!=-1) {
6371 _DEBUG(("Defragmenter: There are %ld blocks of free space after the extent at block %ld.\n", freeafter
, key
));
6374 /* Move (part of) data located in next extent to this free space. */
6376 _DEBUG(("Defragmenter: Filling the gap.\n"));
6378 /* The function below can be called multiple times in a row. When there is a large
6379 gap in which multiple extents of the file will fit, then these can all be transfered
6380 into the gap at once. */
6382 errorcode
=fillgap(key
);
6387 /* Determine which extent it is which is located directly after the current extent. */
6389 if((block
=skipunmoveable(key
+blocks
))!=-1) {
6390 if(block
==key
+blocks
) {
6392 _DEBUG(("Defragmenter: There was a moveable extent after the extent at block %ld.\n", key
));
6394 /* There was no unmoveable data, so let's move it. */
6396 errorcode
=makefreespace(block
);
6401 _DEBUG(("Defragmenter: Skipped %ld blocks of unmoveable data.\n", block
-(key
+blocks
)));
6403 /* Unmoveable data was skipped. */
6405 if(block
!=next
) { // Mar 20 1999: Check to see if the extent after the unmoveable data is not already the correct one.
6407 if((freeafter
=availablespace(block
, 256))!=-1) {
6409 _DEBUG(("Defragmenter: There are %ld blocks of free space after the unmoveable data.\n", freeafter
));
6413 _DEBUG(("Defragmenter: Clearing some space at block %ld.\n", block
));
6415 if((errorcode
=makefreespace(block
))==0) {
6416 if((freeafter
=availablespace(block
, 256))==-1) {
6417 errorcode
=INTERR_DEFRAGMENTER
;
6420 _DEBUG(("Defragmenter: There are now %ld blocks of cleared space after the unmoveable data.\n", freeafter
));
6425 struct CacheBuffer
*cb
;
6426 struct fsExtentBNode
*ebn
;
6428 if((errorcode
=findextentbnode(next
, &cb
, &ebn
))==0) {
6430 _DEBUG(("Defragmenter: Moved next extent of our extent directly after the unmoveable space (block = %ld).\n", block
));
6432 if((errorcode
=moveextent(ebn
, block
, MIN(freeafter
, BE2W(ebn
->be_blocks
))))==0) {
6433 globals
->block_defragptr
=block
;
6439 errorcode
=INTERR_DEFRAGMENTER
;
6444 /* Extent after unmoveable data is already correct, so no need to move it. */
6446 globals
->block_defragptr
=block
;
6451 errorcode
=INTERR_DEFRAGMENTER
;
6456 errorcode
=INTERR_DEFRAGMENTER
;
6462 _DEBUG(("Defragmenter: Found an extent at block %ld which must be moved away.\n", globals
->block_defragptr
));
6464 errorcode
=makefreespace(globals
->block_defragptr
);
6471 if((errorcode
=findmatch_fromend(globals
->block_defragptr
, free
, &bestkey
))==0) {
6473 struct CacheBuffer
*cb
;
6474 struct fsExtentBNode
*ebn
;
6476 if((errorcode
=findextentbnode(bestkey
, &cb
, &ebn
))==0) {
6478 _DEBUG(("Defragmenter: Moving a new first Extent to %ld\n", globals
->block_defragptr
));
6480 errorcode
=moveextent(ebn
, globals
->block_defragptr
, MIN(free
, BE2W(ebn
->be_blocks
)));
6484 _DEBUG(("Defragmenter: Nothing more to optimize.\n"));
6492 errorcode
=INTERR_DEFRAGMENTER
;
6495 _DEBUG(("Defragmenter: Exiting with errorcode %ld\n\n",errorcode
));
6504 if (block at block_optimizeptr is full) {
6506 determine in which extent block_optimizeptr is located.
6508 if (not located in extent) {
6509 skip unmoveable data: add 1 to block_optimizeptr.
6511 else if (extent is first extent OR previous extent is located before block_optimizeptr) {
6512 if (extent is last extent (as well)) {
6513 file was defragmented: set block_optimizeptr to point just after this extent.
6516 determine if there is free space located after this extent.
6518 if (there is free space) {
6519 move (part of) data located in next extent to this free space.
6523 determine which extent it is which is located directly after the current extent.
6525 if (no such extent exists) {
6526 skip unmoveable data
6528 if (no free space after unmoveable data) {
6529 make some free space by moving data.
6531 move (part of) data located in next extent to the (newly made) free space: set block_optimizeptr in this part.
6534 make some free space first by moving data.
6540 make some free space by moving data at block_optimizeptr.
6545 determine amount of free space.
6547 look for an extent-chain equal to the amount of free space beyond this location.
6549 if (found suitable extent-chain) {
6550 move data to block_optimizeptr; set block_optimizeptr to point just after this data.
6553 scan for ANY 'first' extent beyond this location.
6556 optimization is done.
6559 move found 'first' extent to block_optimizeptr.
6568 /* The simple purpose of the SFS DosList handler task is to
6569 provide the following non-blocking functions:
6571 - Adding a VolumeNode to the DosList
6574 - Removing a VolumeNode from the DosList (synchronously)
6577 All messages sent to the DosList handler are freed by
6578 the DosList handler itself. This is to avoid having to
6579 wait for the reply and then free the message yourself.
6589 static void sdlhtask(void)
6592 struct ExecBase
*SysBase
=globals
->sysBase
;
6594 struct DosLibrary
*DOSBase
;
6596 if((DOSBase
=(struct DosLibrary
*)OpenLibrary("dos.library",37))!=0) {
6598 if(FindPort("SFS DosList handler")==0) {
6599 struct MsgPort
*port
;
6601 if((port
=CreateMsgPort())!=0) {
6602 struct SFSMessage
*sfsm
;
6604 port
->mp_Node
.ln_Name
="SFS DosList handler";
6605 port
->mp_Node
.ln_Pri
=1;
6610 struct DosList
*dol
;
6614 dol
=LockDosList(LDF_WRITE
|LDF_VOLUMES
);
6616 while((sfsm
=(struct SFSMessage
*)GetMsg(port
))!=0) {
6617 if(sfsm
->command
==SFSM_ADD_VOLUMENODE
) {
6618 /* AddDosEntry rejects volumes based on their name and date. */
6620 if(AddDosEntry((struct DosList
*)sfsm
->data
)==DOSFALSE
) {
6621 sfsm
->errorcode
=IoErr();
6624 // if(AddDosEntry((struct DosList *)sfsm->data)==DOSFALSE) {
6625 // errorcode=IoErr();
6626 // FreeDosEntry((struct DosList *)vn);
6630 else if(sfsm
->command
==SFSM_REMOVE_VOLUMENODE
) {
6631 struct DosList
*vn
=(struct DosList
*)sfsm
->data
;
6633 while((dol
=NextDosEntry(dol
, LDF_VOLUMES
))!=0) {
6639 // removevolumenode(dol, (struct DosList *)sfsm->data); /* Dangerous because of DOSBase?? */
6646 UnLockDosList(LDF_WRITE
|LDF_VOLUMES
);
6657 CloseLibrary((struct Library
*)DOSBase
);