1 #include "asmsupport.h"
3 #include <exec/types.h>
5 #include <proto/exec.h>
6 #include <proto/utility.h>
8 #include <utility/tagitem.h>
11 #include "objects_protos.h"
13 #include "adminspaces_protos.h"
14 #include "cachebuffers_protos.h"
16 #include "locks_protos.h"
17 #include "nodes_protos.h"
18 #include "support_protos.h"
19 #include "transactions_protos.h"
20 #include "req_protos.h"
25 extern UBYTE
*fullpath(struct CacheBuffer
*cbstart
,struct fsObject
*o
);
26 extern LONG
readcachebuffercheck(struct CacheBuffer
**,ULONG
,ULONG
);
28 extern BOOL
freeupspace(void);
30 extern LONG
deleteextents(ULONG key
);
32 extern void checknotifyforobject(struct CacheBuffer
*cb
,struct fsObject
*o
,UBYTE notifyparent
);
33 extern void checknotifyforpath(UBYTE
*path
,UBYTE notifyparent
);
35 extern LONG
deletefileslowly(struct CacheBuffer
*cbobject
, struct fsObject
*o
);
37 static LONG
dehashobjectquick(NODE objectnode
, UBYTE
*name
, NODE parentobjectnode
);
38 LONG
simpleremoveobject(struct CacheBuffer
*cb
,struct fsObject
*o
);
39 LONG
locatelockableparent(struct ExtFileLock
*lock
,UBYTE
*path
,struct CacheBuffer
**returned_cb
,struct fsObject
**returned_o
);
41 static void copyobject(struct fsObject
*o2
,struct fsObject
*o
);
43 LONG
findobjectspace(struct CacheBuffer
**io_cb
,struct fsObject
**io_o
,ULONG bytesneeded
);
44 static UBYTE
*emptyspaceinobjectcontainer(struct fsObjectContainer
*oc
);
45 WORD
objectsize(struct fsObject
*o
);
46 UBYTE
*getcomment(struct fsObject
*o
);
47 static WORD
changeobjectsize(struct CacheBuffer
*cb
, struct fsObject
*o
, WORD bytes
);
48 static LONG
deleteobjectnode(NODE objectnode
);
52 LONG
hashobject(BLCK hashblock
, struct fsObjectNode
*on
, NODE nodeno
, UBYTE
*objectname
) {
53 struct CacheBuffer
*cbhash
;
56 /* This function takes a HashBlock pointer, an ObjectNode and an ObjectName.
57 If there is a hashblock, then this function will correctly link the object
58 into the hashchain. If there isn't a hashblock (=0) then this function
61 A transaction must be in progress before calling this function, and the
62 ObjectNode's CacheBuffer must be prepared. */
64 if(hashblock
!=0 && (errorcode
=readcachebuffercheck(&cbhash
, hashblock
, HASHTABLE_ID
))==0) {
65 struct fsHashTable
*ht
=cbhash
->data
;
67 UWORD hashvalue
, hashchain
;
69 hashvalue
=hash(objectname
, globals
->is_casesensitive
);
70 hashchain
=HASHCHAIN(hashvalue
);
71 nexthash
=BE2L(ht
->be_hashentry
[hashchain
]);
73 preparecachebuffer(cbhash
);
75 checksum_writelong_be(cbhash
->data
, &ht
->be_hashentry
[hashchain
], nodeno
);
77 // ht->hashentry[hashchain]=nodeno;
79 if((errorcode
=storecachebuffer_nochecksum(cbhash
))==0) {
80 on
->be_next
=L2BE(nexthash
);
81 on
->be_hash16
=W2BE(hashvalue
);
90 LONG
setrecycledinfo(ULONG deletedfiles
, ULONG deletedblocks
) {
91 struct CacheBuffer
*cb
;
94 if((errorcode
=readcachebuffercheck(&cb
,globals
->block_root
,OBJECTCONTAINER_ID
))==0) {
95 struct fsRootInfo
*ri
=(struct fsRootInfo
*)((UBYTE
*)cb
->data
+globals
->bytes_block
-sizeof(struct fsRootInfo
));
97 preparecachebuffer(cb
);
99 checksum_writelong_be(cb
->data
, &ri
->be_deletedfiles
, deletedfiles
);
100 checksum_writelong_be(cb
->data
, &ri
->be_deletedblocks
, deletedblocks
);
102 // ri->deletedfiles=deletedfiles;
103 // ri->deletedblocks=deletedblocks;
105 errorcode
=storecachebuffer_nochecksum(cb
);
113 LONG
setrecycledinfodiff(LONG deletedfiles
, LONG deletedblocks
) {
114 struct CacheBuffer
*cb
;
117 if((errorcode
=readcachebuffercheck(&cb
,globals
->block_root
,OBJECTCONTAINER_ID
))==0) {
118 struct fsRootInfo
*ri
=(struct fsRootInfo
*)((UBYTE
*)cb
->data
+globals
->bytes_block
-sizeof(struct fsRootInfo
));
120 preparecachebuffer(cb
);
122 checksum_writelong_be(cb
->data
, &ri
->be_deletedfiles
, BE2L(ri
->be_deletedfiles
) + deletedfiles
);
123 checksum_writelong_be(cb
->data
, &ri
->be_deletedblocks
, BE2L(ri
->be_deletedblocks
) + deletedblocks
);
125 // ri->deletedfiles+=deletedfiles;
126 // ri->deletedblocks+=deletedblocks;
128 errorcode
=storecachebuffer_nochecksum(cb
);
136 LONG
getrecycledinfo(ULONG
*returned_deletedfiles
, ULONG
*returned_deletedblocks
) {
137 struct CacheBuffer
*cb
;
140 if((errorcode
=readcachebuffercheck(&cb
,globals
->block_root
,OBJECTCONTAINER_ID
))==0) {
141 struct fsRootInfo
*ri
=(struct fsRootInfo
*)((UBYTE
*)cb
->data
+globals
->bytes_block
-sizeof(struct fsRootInfo
));
143 *returned_deletedfiles
=BE2L(ri
->be_deletedfiles
);
144 *returned_deletedblocks
=BE2L(ri
->be_deletedblocks
);
152 static LONG
safedeleteobjectquick(struct CacheBuffer
*cb
, struct fsObject
*o
, WORD sendnotify
) {
153 struct CacheBuffer
*cbdd
;
154 struct fsObject
*odd
;
155 UBYTE
*s
=globals
->string2
;
160 while((*s
++=*n
++)!=0) {
165 len
-=(globals
->max_name_length
-4);
172 if((errorcode
=readobject(RECYCLEDNODE
, &cbdd
, &odd
))==0) {
173 struct CacheBuffer
*cb2
;
177 lockcachebuffer(cbdd
);
183 if((errorcode
=locateobject(globals
->string2
, &cb2
, &o2
))==ERROR_OBJECT_NOT_FOUND
) {
184 ULONG blocks
=(BE2L(o
->object
.file
.be_size
)+globals
->bytes_block
-1)>>globals
->shifts_block
;
186 globals
->internalrename
=TRUE
;
188 if((errorcode
=renameobject2(cb
, o
, cbdd
, odd
, globals
->string2
, sendnotify
))==0) {
189 errorcode
=setrecycledinfodiff(1, blocks
);
192 globals
->internalrename
=FALSE
;
199 *s2
++=((count
& 0xF00)>>8)+65;
200 *s2
++=((count
& 0x0F0)>>4)+65;
201 *s2
++=(count
& 0x00F)+65;
205 errorcode
=INTERR_SAFE_DELETE
;
211 unlockcachebuffer(cbdd
);
214 unlockcachebuffer(cb
);
216 _XDEBUG((DEBUG_OBJECTS
,"safedeleteobjectquick: exiting with errorcode %ld\n",errorcode
));
224 BOOL
cleanupdeletedfiles(void) {
225 /* This function returns TRUE if atleast one or more files were succesfully
226 deleted. FALSE is returned if no space at all could be freed.
228 This function returns FALSE if there's no recycled directory. */
230 _DEBUG(("cleanupdeletedfiles: entry\n"));
232 if(globals
->has_recycled
!=FALSE
) {
233 struct CacheBuffer
*cbdd
;
234 struct fsObject
*odd
;
236 ULONG filesdeleted
=0;
239 if(readobject(RECYCLEDNODE
, &cbdd
, &odd
)==0 && odd
->object
.dir
.be_firstdirblock
!=0) {
241 lockcachebuffer(cbdd
);
243 while(kbdeleted
<1024 && filesdeleted
<10) {
244 struct CacheBuffer
*cb
=0;
245 struct fsObjectContainer
*oc
;
247 BLCK nextblock
=BE2L(odd
->object
.dir
.be_firstdirblock
);
251 while(nextblock
!=0 && readcachebuffercheck(&cb
, nextblock
, OBJECTCONTAINER_ID
)==0) {
253 nextblock
=BE2L(oc
->be_next
);
265 if(lockable(BE2L(o
->be_objectnode
),EXCLUSIVE_LOCK
)!=DOSFALSE
) {
266 ULONG size
=BE2L(o
->object
.file
.be_size
)>>10;
268 _DEBUG(("cleanupdeletedfiles: deleting %s, objectnode = %ld\n",o
->name
,BE2L(o
->be_objectnode
)));
270 if(deletefileslowly(cb
, o
)==0) {
279 } while(isobject(o
,oc
)!=FALSE
);
281 } while(filedeleted
==FALSE
&& oc
->be_previous
!=0 && readcachebuffercheck(&cb
, BE2L(oc
->be_previous
), OBJECTCONTAINER_ID
)==0);
283 if(oc
->be_previous
==0) {
288 unlockcachebuffer(cbdd
);
291 _DEBUG(("cleanupdeletedfiles: Deleted %ld files for %ld kB worth of space\n",filesdeleted
,kbdeleted
));
293 if(filesdeleted
!=0) {
303 static LONG
deleteobjectquick(struct CacheBuffer
*cb
, struct fsObject
*o
, WORD sendnotify
) {
305 BLCK hashblckno
=BE2L(o
->object
.dir
.be_hashtable
);
306 BLCK extentbnode
=BE2L(o
->object
.file
.be_data
);
310 /* cb & o refer to the object to be deleted.
312 Note: This function deletes an object without first checking if
313 this is allowed. Use deleteobject() instead. */
315 if(sendnotify
!=FALSE
) {
316 notifypath
=fullpath(cb
,o
);
319 if((errorcode
=removeobject(cb
, o
))==0) {
321 /* What we need to do now depends on the type of object we are
322 deleting. For a directory we need to kill its HashTable block,
323 and for a File we need to remove all of its Extents and the
324 used space associated with them. */
326 if((bits
& OTYPE_LINK
)!=0) {
327 _XDEBUG((DEBUG_OBJECTS
,"deleteobject: Object is soft link!\n"));
329 errorcode
=freeadminspace(extentbnode
);
331 else if((bits
& OTYPE_DIR
)!=0) {
332 _XDEBUG((DEBUG_OBJECTS
,"deleteobject: Object is a directory!\n"));
334 errorcode
=freeadminspace(hashblckno
);
337 _XDEBUG((DEBUG_OBJECTS
,"deleteobject: Object is a file\n"));
339 errorcode
=deleteextents(extentbnode
);
342 if(errorcode
==0 && sendnotify
!=FALSE
) {
343 checknotifyforpath(notifypath
,TRUE
);
352 LONG
deleteobject(struct ExtFileLock
*lock
, UBYTE
*path
, WORD sendnotify
) {
353 struct CacheBuffer
*cb
;
358 /* This function deletes the specified object. It will only delete directories
359 if they are empty. All space associated with a file will be marked free. */
361 _XDEBUG((DEBUG_OBJECTS
,"deleteobject: Entry -- deleting object %s\n",path
));
367 objectnode
=lock
->objectnode
;
370 if((errorcode
=readobject(objectnode
,&cb
,&o
))==0) {
371 errorcode
=locateobject2(&path
,&cb
,&o
);
380 if(errorcode
==0 || (errorcode
==ERROR_IS_SOFT_LINK
&& *path
==0)) {
381 if((o
->be_protection
& L2BE(FIBF_DELETE
))!=0) {
382 if(lockable(BE2L(o
->be_objectnode
),EXCLUSIVE_LOCK
)!=DOSFALSE
&& (o
->bits
& OTYPE_UNDELETABLE
)==0) {
383 /* Object to be deleted was read correctly by the above locateobject call */
385 if((o
->bits
& OTYPE_DIR
)==0 || o
->object
.dir
.be_firstdirblock
==0) {
386 struct fsObjectContainer
*oc
=cb
->data
;
388 /* At this point we can be sure that the object is allowed
391 if((o
->bits
& OTYPE_DIR
)!=0 || (o
->bits
& OTYPE_LINK
)!=0 || globals
->has_recycled
==FALSE
|| oc
->be_parent
==L2BE(RECYCLEDNODE
)) {
392 errorcode
=deleteobjectquick(cb
, o
, sendnotify
);
395 errorcode
=safedeleteobjectquick(cb
, o
, sendnotify
);
399 errorcode
=ERROR_DIRECTORY_NOT_EMPTY
;
403 errorcode
=ERROR_OBJECT_IN_USE
;
407 errorcode
=ERROR_DELETE_PROTECTED
;
412 _XDEBUG((DEBUG_OBJECTS
,"deleteobject: Exiting with errorcode %ld\n",errorcode
));
419 LONG
removeobjectcontainer(struct CacheBuffer
*cb
) {
420 struct fsObjectContainer
*oc
=cb
->data
;
423 /* Removes an ObjectContainer from a directory chain. Make
424 sure it is empty before removing it! */
426 _XDEBUG((DEBUG_OBJECTS
,"removeobjectcontainer: entry\n"));
430 if(oc
->be_next
!=0 && oc
->be_next
!=oc
->bheader
.be_ownblock
) { // BE-BE compare!
431 struct CacheBuffer
*next_cb
;
432 struct fsObjectContainer
*next_oc
;
434 if((errorcode
=readcachebuffercheck(&next_cb
,BE2L(oc
->be_next
),OBJECTCONTAINER_ID
))!=0) {
438 preparecachebuffer(next_cb
);
440 next_oc
=next_cb
->data
;
442 next_oc
->be_previous
=oc
->be_previous
; // BE-BE copy!
443 if((errorcode
=storecachebuffer(next_cb
))!=0) {
448 if(oc
->be_previous
!=0 && oc
->be_previous
!=oc
->bheader
.be_ownblock
) { // BE-BE compare!
449 struct CacheBuffer
*previous_cb
;
450 struct fsObjectContainer
*previous_oc
;
452 if((errorcode
=readcachebuffercheck(&previous_cb
,BE2L(oc
->be_previous
),OBJECTCONTAINER_ID
))!=0) {
456 preparecachebuffer(previous_cb
);
458 previous_oc
=previous_cb
->data
;
460 previous_oc
->be_next
=oc
->be_next
; // BE-BE copy
461 if((errorcode
=storecachebuffer(previous_cb
))!=0) {
466 struct CacheBuffer
*parent_cb
;
467 struct fsObject
*parent_o
;
469 if((errorcode
=readobject(BE2L(oc
->be_parent
),&parent_cb
,&parent_o
))!=0) {
473 preparecachebuffer(parent_cb
);
475 if((parent_o
->bits
& OTYPE_RINGLIST
)!=0) {
476 parent_o
->object
.dir
.be_firstdirblock
=0;
479 parent_o
->object
.dir
.be_firstdirblock
=oc
->be_next
; // BE-BE copy
482 if((errorcode
=storecachebuffer(parent_cb
))!=0) {
487 unlockcachebuffer(cb
);
489 if((errorcode
=freeadminspace(cb
->blckno
))!=0) {
493 // emptycachebuffer(cb);
500 LONG
bumpobject(struct CacheBuffer
*cb
, struct fsObject
*o
) {
501 ULONG newdate
=getdate();
502 ULONG newprotection
=BE2L(o
->be_protection
) & ~FIBF_ARCHIVE
;
504 /* Updates the date of the object and clears the archived bit. */
506 if(newdate
!=BE2L(o
->be_datemodified
) || BE2L(o
->be_protection
)!=newprotection
) {
507 preparecachebuffer(cb
);
509 checksum_writelong_be(cb
->data
, &o
->be_datemodified
, newdate
);
510 checksum_writelong_be(cb
->data
, &o
->be_protection
, newprotection
);
512 // o->datemodified=newdate;
513 // o->protection=newprotection;
515 return(storecachebuffer_nochecksum(cb
));
522 LONG
simpleremoveobject(struct CacheBuffer
*cb
, struct fsObject
*o
) {
523 struct fsObjectContainer
*oc
=cb
->data
;
524 BLCK parent
=BE2L(oc
->be_parent
);
527 /* This function removes the fsObject structure passed in from the passed
528 in CacheBuffer (a fsObjectContainer). If the ObjectContainer becomes
529 completely empty it will be delinked from the ObjectContainer chain and
530 marked free for reuse. newtransaction() must have been called before
531 calling this function.
533 This function doesn't delink the object from the hashchain! */
535 _XDEBUG((DEBUG_OBJECTS
,"simpleremoveobject: Entry\n"));
537 if(BE2L(oc
->be_parent
)==RECYCLEDNODE
) {
539 /* This object is removed from the Recycled directory. */
541 if((errorcode
=setrecycledinfodiff(-1, -((BE2L(o
->object
.file
.be_size
)+globals
->bytes_block
-1)>>globals
->shifts_block
)))!=0) {
546 if(isobject(nextobject(oc
->object
),oc
)==FALSE
) {
547 errorcode
=removeobjectcontainer(cb
);
550 struct fsObject
*nexto
;
555 preparecachebuffer(cb
);
560 words
=(globals
->bytes_block
-((UBYTE
*)nexto
-(UBYTE
*)oc
))>>1;
566 words
=((UBYTE
*)nexto
-(UBYTE
*)o
)>>1;
572 errorcode
=storecachebuffer(cb
);
575 if(errorcode
==0 && (errorcode
=readobject(parent
,&cb
,&o
))==0) { // reading parent block
576 errorcode
=bumpobject(cb
, o
); /* An object was removed from this directory -- update date. */
584 static LONG
dehashobjectquick(NODE objectnode
, UBYTE
*name
, NODE parentobjectnode
) {
585 struct CacheBuffer
*cb
;
589 _XDEBUG((DEBUG_OBJECTS
,"dehashobject: Delinking object %ld (=ObjectNode) from hashchain. Parentnode = %ld\n",objectnode
,parentobjectnode
));
591 /* This function delinks the passed in ObjectNode from its hash-chain. Handy when deleting
592 the object, or when renaming/moving it. newtransaction() must have been called before
593 calling this function. */
595 if((errorcode
=readobject(parentobjectnode
,&cb
,&o
))==0 && o
->object
.dir
.be_hashtable
!=0) {
596 if((errorcode
=readcachebuffercheck(&cb
,BE2L(o
->object
.dir
.be_hashtable
),HASHTABLE_ID
))==0) {
597 struct CacheBuffer
*cbnode
;
598 struct fsObjectNode
*on
;
599 struct fsHashTable
*ht
=cb
->data
;
604 if((errorcode
=findnode(globals
->block_objectnoderoot
, sizeof(struct fsObjectNode
), objectnode
, &cbnode
, (struct fsNode
**)&on
))==0) {
607 _XDEBUG((DEBUG_OBJECTS
,"dehashobject: Read HashTable block of parent object of object to be delinked\n"));
609 lockcachebuffer(cbnode
);
611 hashchain
=HASHCHAIN(hash(name
, globals
->is_casesensitive
));
612 nexthash
=BE2L(ht
->be_hashentry
[hashchain
]);
614 if(nexthash
==objectnode
) {
615 /* The hashtable directly points to the fsObject to be delinked. We simply
616 modify the Hashtable to point to the new nexthash entry. */
618 _XDEBUG((DEBUG_OBJECTS
,"dehashobject: The hashtable points directly to the to be delinked object\n"));
620 preparecachebuffer(cb
);
622 checksum_writelong_be(cb
->data
, &ht
->be_hashentry
[hashchain
], BE2L(on
->be_next
));
624 // ht->hashentry[hashchain]=on->next;
626 errorcode
=storecachebuffer_nochecksum(cb
);
629 struct CacheBuffer
*cb
=0;
630 struct fsObjectNode
*onsearch
=0;
632 _XDEBUG((DEBUG_OBJECTS
,"dehashobject: Walking through hashchain\n"));
634 while(nexthash
!=0 && nexthash
!=objectnode
) {
635 if((errorcode
=findnode(globals
->block_objectnoderoot
, sizeof(struct fsObjectNode
), nexthash
, &cb
, (struct fsNode
**)&onsearch
))!=0) {
639 nexthash
=BE2L(onsearch
->be_next
);
644 /* Previous fsObjectNode found in hash chain. Modify the fsObjectNode to 'skip' the
645 ObjectNode which is being delinked from the hash chain. */
647 preparecachebuffer(cb
);
649 checksum_writelong_be(cb
->data
, &onsearch
->be_next
, BE2L(on
->be_next
));
651 // onsearch->next=on->next;
653 errorcode
=storecachebuffer_nochecksum(cb
);
656 req("Hashchain of object %ld is\ncorrupt or incorrectly linked.", "Ok", objectnode
);
658 /*** This is strange. We have been looking for the fsObjectNode which is located before the
659 passed in fsObjectNode in the hash-chain. However, we never found the
660 fsObjectNode reffered to in the hash-chain! Has to be somekind
661 of internal error... */
663 errorcode
=ERROR_OBJECT_NOT_FOUND
;
668 unlockcachebuffer(cbnode
);
671 unlockcachebuffer(cb
);
680 static LONG
createobjecttagitem(struct CacheBuffer
**io_cb
, struct fsObject
**io_o
, UBYTE
*objectname
, struct TagItem
*tags
) {
681 struct CacheBuffer
*cb
=*io_cb
;
682 struct fsObject
*o
=*io_o
;
685 /* io_cb & io_o refer to the direct parent of the new object. Objectname is the
686 name of the new object (name only). Use the Tags to pass a comment (important
687 since you can't change the size of the Object afterwards to accomodate one).
689 io_cb & io_o will not be locked, so make sure you lock the parent if you intend
690 to use it after this function.
692 This function updates the parent's date and Archive bit. It also check if the
693 object already exists to avoid duplicates.
695 If this function returns no error it will return in io_cb & io_o the new object
698 _XDEBUG((DEBUG_OBJECTS
,"createobjecttags: Creating object '%s' in dir '%s'.\n",objectname
,(*io_o
)->name
));
700 if(BE2L((*io_o
)->be_objectnode
)!=RECYCLEDNODE
|| globals
->internalrename
!=FALSE
) {
703 lockcachebuffer(*io_cb
);
705 /* Either duplicates are allowed or the object doesn't exist yet: */
707 if(((tag
=FindTagItem(CO_ALLOWDUPLICATES
, tags
))!=0 && tag
->ti_Data
!=FALSE
) || (errorcode
=locateobject(objectname
, &cb
, &o
))==ERROR_OBJECT_NOT_FOUND
) {
709 unlockcachebuffer(*io_cb
);
711 _XDEBUG((DEBUG_OBJECTS
,"createobjecttags: Object didn't exist, so we can safely create it.\n"));
715 if((tag
=FindTagItem(CO_UPDATEPARENT
, tags
))!=0 && tag
->ti_Data
!=FALSE
) {
716 errorcode
=bumpobject(*io_cb
, *io_o
); /* Update the date and the ARCHIVE bit of the parent directory. */
721 ULONG hashblock
=BE2L((*io_o
)->object
.dir
.be_hashtable
);
723 objectsize
=sizeof(struct fsObject
)+strlen(objectname
)+2;
725 if((tag
=FindTagItem(CO_COMMENT
, tags
))!=0) {
726 objectsize
+=strlen((UBYTE
*)tag
->ti_Data
);
729 if((errorcode
=findobjectspace(io_cb
, io_o
, objectsize
))==0) {
730 struct TagItem
*tstate
=tags
;
731 struct fsObject
*o
=*io_o
;
733 UBYTE
*objname
=objectname
;
737 if((tag
=FindTagItem(CO_BITS
, tags
))!=0) {
738 o
->bits
=tag
->ti_Data
;
741 /* Setting defaults in case tags aren't specified: */
745 o
->be_protection
=L2BE(FIBF_READ
|FIBF_WRITE
|FIBF_EXECUTE
|FIBF_DELETE
);
746 o
->be_datemodified
=L2BE(getdate());
754 *name
=0; /* zero byte for comment */
756 while((tag
=NextTagItem(&tstate
))!=0) {
757 switch(tag
->ti_Tag
) {
759 o
->be_owneruid
=W2BE(tag
->ti_Data
>>16);
760 o
->be_ownergid
=W2BE(tag
->ti_Data
& 0xFFFF);
762 case CO_DATEMODIFIED
:
763 o
->be_datemodified
=L2BE(tag
->ti_Data
);
766 o
->be_protection
=L2BE(tag
->ti_Data
);
770 UBYTE
*comment
=(UBYTE
*)tag
->ti_Data
;
779 if((o
->bits
& OTYPE_DIR
)==0) {
780 o
->object
.file
.be_size
=L2BE(tag
->ti_Data
);
784 if((o
->bits
& OTYPE_DIR
)==0) {
785 o
->object
.file
.be_data
=L2BE(tag
->ti_Data
);
788 case CO_FIRSTDIRBLOCK
:
789 if((o
->bits
& OTYPE_DIR
)!=0) {
790 o
->object
.dir
.be_firstdirblock
=L2BE(tag
->ti_Data
);
796 if(errorcode
==0) { // ObjectNode reuse or creation:
797 struct CacheBuffer
*cbnode
;
798 struct fsObjectNode
*on
;
800 if((tag
=FindTagItem(CO_OBJECTNODE
, tags
))!=0) {
802 o
->be_objectnode
=L2BE(tag
->ti_Data
);
804 if((errorcode
=findnode(globals
->block_objectnoderoot
, sizeof(struct fsObjectNode
), BE2L(o
->be_objectnode
), &cbnode
, (struct fsNode
**)&on
))==0) {
805 preparecachebuffer(cbnode
);
811 if((errorcode
=createnode(globals
->block_objectnoderoot
, sizeof(struct fsObjectNode
), &cbnode
, (struct fsNode
**)&on
, &nodeno
))==0) {
812 on
->be_hash16
=W2BE(hash(o
->name
, globals
->is_casesensitive
));
813 o
->be_objectnode
=L2BE(nodeno
);
818 /* CacheBuffer cbnode is prepared. */
820 on
->node
.be_data
=L2BE((*io_cb
)->blckno
);
822 if((tag
=FindTagItem(CO_HASHOBJECT
, tags
))!=0 && tag
->ti_Data
!=FALSE
) {
823 errorcode
=hashobject(hashblock
, on
, BE2L(o
->be_objectnode
), objectname
);
827 errorcode
=storecachebuffer(cbnode
);
830 dumpcachebuffer(cbnode
);
835 if(errorcode
==0) { // HashBlock reuse or creation:
836 if((o
->bits
& OTYPE_DIR
)!=0) {
837 struct CacheBuffer
*hashcb
;
839 if((tag
=FindTagItem(CO_HASHBLOCK
, tags
))!=0) {
840 o
->object
.dir
.be_hashtable
=L2BE(tag
->ti_Data
);
842 else if((errorcode
=allocadminspace(&hashcb
))==0) { // Create a new HashTable block.
843 struct fsHashTable
*ht
=hashcb
->data
;
845 o
->object
.dir
.be_hashtable
=L2BE(hashcb
->blckno
);
847 ht
->bheader
.id
=HASHTABLE_ID
;
848 ht
->bheader
.be_ownblock
=L2BE(hashcb
->blckno
);
849 ht
->be_parent
=o
->be_objectnode
; // BE-BE copy!
851 errorcode
=storecachebuffer(hashcb
);
856 if(errorcode
==0) { // SoftLink creation:
857 if((o
->bits
& (OTYPE_LINK
|OTYPE_HARDLINK
))==OTYPE_LINK
) {
858 if((tag
=FindTagItem(CO_SOFTLINK
, tags
))!=0) {
859 struct CacheBuffer
*cb
;
861 if((errorcode
=allocadminspace(&cb
))==0) {
862 struct fsSoftLink
*sl
=cb
->data
;
863 UBYTE
*dest
=sl
->string
;
864 UBYTE
*softlink
=(UBYTE
*)tag
->ti_Data
;
866 o
->object
.file
.be_data
=L2BE(cb
->blckno
);
868 sl
->bheader
.id
=SOFTLINK_ID
;
869 sl
->bheader
.be_ownblock
=L2BE(cb
->blckno
);
870 sl
->be_parent
=o
->be_objectnode
; // BE-BE copy
874 while((*dest
++=*softlink
++)!=0) {
877 errorcode
=storecachebuffer(cb
);
884 dumpcachebuffer(*io_cb
);
891 errorcode
=ERROR_OBJECT_EXISTS
;
894 unlockcachebuffer(*io_cb
);
898 errorcode
=ERROR_OBJECT_IN_USE
; /* Occurs when someone tries to create something in the recycled directory. */
906 static void copyobject(struct fsObject
*o2
,struct fsObject
*o
) {
907 o
->be_objectnode
=o2
->be_objectnode
; // BE-BE copy
908 o
->be_owneruid
=o2
->be_owneruid
; // BE-BE copy
909 o
->be_ownergid
=o2
->be_ownergid
; // BE-BE copy
910 o
->be_protection
=o2
->be_protection
; // BE-BE copy
911 o
->be_datemodified
=o2
->be_datemodified
; // BE-BE copy
914 if((o
->bits
& OTYPE_DIR
)!=0) {
915 o
->object
.dir
.be_firstdirblock
=o2
->object
.dir
.be_firstdirblock
; // BE-BE copy
916 o
->object
.dir
.be_hashtable
=o2
->object
.dir
.be_hashtable
; // BE-BE copy
919 o
->object
.file
.be_data
=o2
->object
.file
.be_data
; // BE-BE copy
920 o
->object
.file
.be_size
=o2
->object
.file
.be_size
; // BE-BE copy
926 LONG
setcomment2(struct CacheBuffer
*cb
, struct fsObject
*o
, UBYTE
*comment
) {
927 UWORD commentlength
=strlen(comment
);
930 if(commentlength
<80) {
931 UBYTE
*oldcomment
=getcomment(o
);
932 UWORD oldcommentlength
=strlen(oldcomment
);
934 if(oldcommentlength
!=0 || commentlength
!=0) {
935 if(changeobjectsize(cb
, o
, commentlength
- oldcommentlength
)==TRUE
) {
936 while((*oldcomment
++=*comment
++)!=0) {
939 if((errorcode
=storecachebuffer(cb
))==0) {
940 checknotifyforobject(cb
,o
,TRUE
);
944 struct fsObject
*oldo
;
945 UBYTE object
[sizeof(struct fsObject
)+110+80];
946 NODE parent
=BE2L(((struct fsObjectContainer
*)cb
->data
)->be_parent
);
948 oldo
=(struct fsObject
*)object
;
950 CopyMem(o
,object
,(UBYTE
*)nextobject(o
)-(UBYTE
*)o
);
952 if((errorcode
=simpleremoveobject(cb
,o
))==0) {
953 if((errorcode
=readobject(parent
, &cb
, &o
))==0) { // out: cb & o = Parent of Object to get new comment.
957 if((oldo
->bits
& OTYPE_DIR
)!=0) {
959 tag2
=CO_FIRSTDIRBLOCK
;
961 val1
=BE2L(oldo
->object
.dir
.be_hashtable
);
962 val2
=BE2L(oldo
->object
.dir
.be_firstdirblock
);
968 val1
=BE2L(oldo
->object
.file
.be_data
);
969 val2
=BE2L(oldo
->object
.file
.be_size
);
972 /* We've removed the object, but didn't remove it from the hashchain.
973 This means functions like locateobject could stumble upon the
974 removed object's ObjectNode, and follow it to a non-existing
975 object. That's why the CO_ALLOWDUPLICATES tag is passed. */
977 /* In goes the Parent cb & o, out comes the New object's cb & o :-) */
979 struct TagItem tags
[] = {
980 { CO_ALLOWDUPLICATES
, TRUE
},
981 { CO_COMMENT
, (IPTR
)comment
},
982 { CO_OBJECTNODE
, BE2L(oldo
->be_objectnode
) },
983 { CO_PROTECTION
, BE2L(oldo
->be_protection
) },
984 { CO_DATEMODIFIED
, BE2L(oldo
->be_datemodified
) },
985 { CO_OWNER
, (BE2W(oldo
->be_owneruid
)<<16) + BE2W(oldo
->be_ownergid
) },
986 { CO_BITS
, oldo
->bits
},
992 if((errorcode
=createobjecttagitem(&cb
, &o
, oldo
->name
, tags
))==0) {
994 if((errorcode
=storecachebuffer(cb
))==0) {
995 checknotifyforobject(cb
,o
,TRUE
);
1004 errorcode
=ERROR_COMMENT_TOO_BIG
;
1013 LONG
setcomment(struct ExtFileLock
*lock
, UBYTE
*path
, UBYTE
*comment
) {
1014 struct CacheBuffer
*cb
;
1018 if((errorcode
=locatelockableobject(lock
, path
, &cb
, &o
))==0) { // out: cb & o = Object to get new comment.
1019 errorcode
=setcomment2(cb
, o
, comment
);
1027 LONG
locatelockableparent(struct ExtFileLock
*lock
,UBYTE
*path
,struct CacheBuffer
**returned_cb
,struct fsObject
**returned_o
) {
1031 errorcode
=locatelockableobject(lock
,"/",returned_cb
,returned_o
);
1034 UBYTE
*objectname
=FilePart(path
);
1035 UBYTE c
=*objectname
;
1039 errorcode
=locatelockableobject(lock
,path
,returned_cb
,returned_o
);
1049 LONG
locateparent(struct ExtFileLock
*lock
, UBYTE
*path
, struct CacheBuffer
**returned_cb
, struct fsObject
**returned_o
) {
1053 errorcode
=locateobjectfromlock(lock
,"/",returned_cb
,returned_o
);
1056 UBYTE
*objectname
=FilePart(path
);
1057 UBYTE c
=*objectname
;
1061 errorcode
=locateobjectfromlock(lock
,path
,returned_cb
,returned_o
);
1071 LONG
lockfile(struct ExtFileLock
*lock
, UBYTE
*path
, LONG accessmode
,struct ExtFileLock
**returned_lock
) {
1074 /* Locks a file -- ERROR_OBJECT_WRONG_TYPE is returned if a dir was attempted to be locked. */
1076 if((errorcode
=lockobject(lock
, path
, accessmode
, returned_lock
))==0) {
1077 if(((*returned_lock
)->bits
& EFL_FILE
)==0) { // You're not allowed to open directories or softlinks as files.
1078 freelock(*returned_lock
);
1079 errorcode
=ERROR_OBJECT_WRONG_TYPE
;
1088 LONG
findcreate(struct ExtFileLock
**returned_lock
, UBYTE
*path
, LONG packettype
, UBYTE
*softlink
) {
1089 struct ExtFileLock
*lock
;
1090 UBYTE create
,delete;
1094 /* Used to open files, create files and create directories.
1096 First we check if the file mentioned exists, so we try to locate it.
1097 If the file does exist then depending on the packettype we need to
1098 open it or delete it. If we had to delete the file/directory then
1099 we create a new one in its place. */
1101 /* There seems to be some confusion as to what ACTION_FINDUPDATE is supposed
1102 to do. The 3 modes defined for the Amiga all work slightly different:
1104 - SHARED_LOCK or EXCLUSIVE_LOCK.
1105 - Creates a new file if one didn't exist.
1106 - Deletes existing file if one existed.
1108 ACTION_FINDINPUT: SHARED_LOCK, NO CREATE, NO DELETE
1109 ACTION_FINDUPDATE (1.3): EXCLUSIVE_LOCK, NO CREATE, NO DELETE
1110 ACTION_FINDUPDATE (2.0): SHARED_LOCK, CREATE, NO DELETE
1111 ACTION_FINDOUTPUT: EXCLUSIVE_LOCK, CREATE, DELETE
1112 ACTION_DELETE_OBJECT: EXCLUSIVE_LOCK, NO CREATE, DELETE :-) */
1114 path
=validatepath(path
);
1116 UBYTE
*s
=FilePart(path
);
1119 return(ERROR_INVALID_COMPONENT_NAME
);
1123 if(packettype
==ACTION_FINDINPUT
) {
1124 accessmode
=SHARED_LOCK
;
1128 _XDEBUG((DEBUG_OBJECTS
,"ACTION_FINDINPUT: %s\n",path
));
1130 else if(packettype
==ACTION_FINDOUTPUT
|| packettype
==ACTION_MAKE_LINK
) {
1131 accessmode
=EXCLUSIVE_LOCK
;
1135 _XDEBUG((DEBUG_OBJECTS
,"ACTION_FINDOUTPUT/ACTION_MAKE_LINK: %s\n",path
));
1137 else if(packettype
==ACTION_CREATE_DIR
) {
1138 accessmode
=EXCLUSIVE_LOCK
;
1142 _XDEBUG((DEBUG_OBJECTS
,"ACTION_CREATE_DIR: %s\n",path
));
1144 else { // if(packettype==ACTION_FINDUPDATE)
1145 accessmode
=SHARED_LOCK
;
1149 _XDEBUG((DEBUG_OBJECTS
,"ACTION_FINDUPDATE: %s\n",path
));
1151 else if(packettype==ACTION_DELETE_OBJECT) {
1155 } just an example... :-) */
1160 lock
=*returned_lock
;
1162 if(delete==0 && create
==0) {
1163 errorcode
=lockfile(lock
,path
,accessmode
,returned_lock
);
1166 struct CacheBuffer
*cb
;
1169 errorcode
=locateobjectfromlock(lock
,path
,&cb
,&o
);
1171 /* 0, NO DELETE, CREATE
1172 0, DELETE, NO CREATE
1174 OBJECT_NOT_FOUND, NO DELETE, CREATE
1175 OBJECT_NOT_FOUND, DELETE, NO CREATE
1176 OBJECT_NOT_FOUND, DELETE, CREATE */
1178 if(errorcode
==0 && delete==0) {
1179 if(packettype
==ACTION_CREATE_DIR
) {
1180 errorcode
=ERROR_OBJECT_EXISTS
;
1183 errorcode
=lockfile(lock
,path
,accessmode
,returned_lock
);
1186 else if(errorcode
==0 || errorcode
==ERROR_OBJECT_NOT_FOUND
) {
1187 if(delete==1 && create
==0) { // unused
1190 if((errorcode
=deleteobject(lock
, path
, TRUE
))==0) {
1194 deletetransaction();
1199 LONG lasterrorcode
=errorcode
;
1203 /* When we get here, we ALWAYS need to create a new object (possible
1204 after having deleted any existing objects) */
1208 if(lasterrorcode
==0 && delete==1) {
1209 if((o
->bits
& OTYPE_DIR
)!=0) {
1211 /* We are not allowed to overwrite directories (even if they're empty) */
1213 errorcode
=ERROR_OBJECT_EXISTS
;
1216 errorcode
=deleteobject(lock
, path
, FALSE
); /* Implicit deletes should not send a notify! */
1223 _XDEBUG((DEBUG_OBJECTS
,"findcreate: locating lockable parent\n"));
1225 if(errorcode
==0 && (errorcode
=locateparent(lock
,path
,&cb
,&o
))==0) { // was locatelockableparent()
1228 _XDEBUG((DEBUG_OBJECTS
,"findcreate: creating object\n"));
1230 if(packettype
==ACTION_CREATE_DIR
) {
1233 else if(packettype
==ACTION_MAKE_LINK
) {
1237 struct TagItem tags
[] = {
1239 { CO_HASHOBJECT
, TRUE
},
1240 { CO_SOFTLINK
, (IPTR
)softlink
},
1241 { CO_UPDATEPARENT
, TRUE
},
1245 if((errorcode
=createobjecttagitem(&cb
, &o
, FilePart(path
), tags
))==0) {
1247 _XDEBUG((DEBUG_OBJECTS
,"findcreate: New object is now complete\n"));
1249 if((errorcode
=storecachebuffer(cb
))==0) {
1251 lockcachebuffer(cb
);
1253 if(packettype
==ACTION_MAKE_LINK
) {
1254 checknotifyforobject(cb
,o
,TRUE
);
1256 else if((errorcode
=lockobject(lock
, path
, accessmode
, returned_lock
))==0) {
1257 if(packettype
==ACTION_CREATE_DIR
) {
1258 checknotifyforobject(cb
,o
,TRUE
);
1261 (*returned_lock
)->bits
|=EFL_MODIFIED
;
1265 unlockcachebuffer(cb
);
1271 deletetransaction();
1276 } while(errorcode
==ERROR_DISK_FULL
&& freeupspace()!=FALSE
);
1286 LONG
findobjectspace(struct CacheBuffer
**io_cb
, struct fsObject
**io_o
, ULONG bytesneeded
) {
1287 struct CacheBuffer
*cbparent
=*io_cb
;
1288 struct fsObject
*oparent
=*io_o
;
1289 struct CacheBuffer
*cb
;
1290 ULONG nextblock
=BE2L(oparent
->object
.dir
.be_firstdirblock
);
1293 _XDEBUG((DEBUG_OBJECTS
,"findobjectspace: Looking for %ld bytes in directory with ObjectNode number %ld (in block %ld)\n",bytesneeded
,BE2L((*io_o
)->be_objectnode
),(*io_cb
)->blckno
));
1295 /* This function will look in the directory indicated by io_o
1296 for an ObjectContainer block which contains bytesneeded free
1297 bytes. If none is found then this function simply creates a
1298 new ObjectContainer and adds that to the indicated directory.
1300 If OTYPE_QUICKDIR is set then only the first dir block is
1301 searched for enough free space, and if none is found a new
1302 block is added immediately.
1304 As this function may need to modify the disk, an operation
1305 should be in progress before calling this function. */
1307 lockcachebuffer(cbparent
);
1309 while(nextblock
!=0 && (errorcode
=readcachebuffercheck(&cb
,nextblock
,OBJECTCONTAINER_ID
))==0) {
1310 struct fsObjectContainer
*oc
=cb
->data
;
1313 /* We need to find out how much free space this ObjectContainer has */
1315 emptyspace
=emptyspaceinobjectcontainer(oc
);
1317 if((UBYTE
*)oc
+globals
->bytes_block
-emptyspace
>= bytesneeded
) {
1318 /* We found enough space in one of the ObjectContainer blocks!!
1319 We return a struct fsObject *. */
1321 preparecachebuffer(cb
);
1324 *io_o
=(struct fsObject
*)emptyspace
;
1329 if((oparent
->bits
& OTYPE_QUICKDIR
)!=0 || ((oparent
->bits
& OTYPE_RINGLIST
)!=0 && oc
->be_next
==oparent
->object
.dir
.be_firstdirblock
)) { // BE-BE compare
1333 nextblock
=BE2L(oc
->be_next
);
1338 struct CacheBuffer
*cb
;
1340 /* If we get here, we traversed the *entire* directory (ough!) and found no empty
1341 space large enough for our entry. We allocate new space and add it to this
1344 if((errorcode
=allocadminspace(&cb
))==0) {
1345 struct fsObjectContainer
*oc
=cb
->data
;
1346 UBYTE ringlist
=oparent
->bits
& OTYPE_RINGLIST
;
1348 _XDEBUG((DEBUG_OBJECTS
,"findobjectspace: No room was found, allocated new block at %ld\n",cb
->blckno
));
1350 /* Allocated new block. We will now link it to the START of the directory chain
1351 so the new free space can be found quickly when more entries need to be added. */
1353 oc
->bheader
.id
=OBJECTCONTAINER_ID
;
1354 oc
->bheader
.be_ownblock
=L2BE(cb
->blckno
);
1355 oc
->be_parent
=oparent
->be_objectnode
; // BE-BE copy
1356 oc
->be_next
=oparent
->object
.dir
.be_firstdirblock
; // BE-BE copy
1359 preparecachebuffer(cbparent
);
1361 oparent
->object
.dir
.be_firstdirblock
=L2BE(cb
->blckno
);
1363 if((errorcode
=storecachebuffer(cbparent
))==0) {
1364 struct CacheBuffer
*cbnext
;
1366 if(oc
->be_next
!=0 && (errorcode
=readcachebuffercheck(&cbnext
,BE2L(oc
->be_next
),OBJECTCONTAINER_ID
))==0) {
1367 struct fsObjectContainer
*ocnext
=cbnext
->data
;
1368 BLCK lastblock
=BE2L(ocnext
->be_previous
);
1370 preparecachebuffer(cbnext
);
1372 ocnext
->be_previous
=L2BE(cb
->blckno
);
1374 if((errorcode
=storecachebuffer(cbnext
))==0 && ringlist
!=0) {
1376 oc
->be_previous
=L2BE(lastblock
);
1378 if((errorcode
=readcachebuffercheck(&cbnext
,lastblock
,OBJECTCONTAINER_ID
))==0) {
1379 ocnext
=cbnext
->data
;
1381 preparecachebuffer(cbnext
);
1383 checksum_writelong_be(cbnext
->data
, &ocnext
->be_next
, cb
->blckno
);
1385 // ocnext->next=cb->blckno;
1387 errorcode
=storecachebuffer_nochecksum(cbnext
);
1391 else if(ringlist
!=0) {
1392 oc
->be_previous
=L2BE(cb
->blckno
);
1393 oc
->be_next
=L2BE(cb
->blckno
);
1401 dumpcachebuffer(cb
);
1406 unlockcachebuffer(cbparent
);
1413 static LONG
deleteobjectnode(NODE objectnode
) {
1414 struct CacheBuffer
*cb
;
1415 struct fsObjectNode
*on
;
1418 _XDEBUG((DEBUG_NODES
,"deleteobjectnode: Deleting Node %ld",objectnode
));
1420 if((errorcode
=findnode(globals
->block_objectnoderoot
, sizeof(struct fsObjectNode
), objectnode
, &cb
, (struct fsNode
**)&on
))==0) {
1421 errorcode
=deletenode(globals
->block_objectnoderoot
, cb
, (struct fsNode
*)on
, sizeof(struct fsObjectNode
));
1429 struct fsObject
*findobjectbyname(struct fsObjectContainer
*oc
, UBYTE
*name
) {
1430 struct fsObject
*o
=oc
->object
;
1432 while(isobject(o
, oc
)!=FALSE
) {
1433 UBYTE
*name1
=o
->name
;
1436 if(globals
->is_casesensitive
!=FALSE
) {
1438 if(*name1
!=*name2
) {
1447 if(upperchar(*name1
)!=upperchar(*name2
)) {
1455 if(*name1
==0 && (*name2
==0 || *name2
=='/')) {
1467 LONG
scandir(struct CacheBuffer
**io_cb
, struct fsObject
**io_o
, UBYTE
*name
) {
1468 struct CacheBuffer
*cb
;
1469 BLCK hashblock
=BE2L((*io_o
)->object
.dir
.be_hashtable
);
1472 /* Scans a directory for the object with the name /name/. The directory
1473 to be scanned is given in *io_cb & *io_o. The resulting object (if any)
1474 is returned in *io_cb and *io_o.
1476 This function handles directories with no hashblock correctly. */
1479 if((errorcode
=readcachebuffercheck(&cb
, hashblock
, HASHTABLE_ID
))==0) {
1480 struct fsHashTable
*ht
=cb
->data
;
1481 struct fsObjectNode
*on
;
1483 NODE nextobjectnode
,objectnode
;
1485 /* cb is a HashTable block. name is used to calculate the correct
1486 hash-value and the correct hash-chain is traversed until either
1487 the hash chain ends, or the name is located. */
1489 hash16
=hash(name
, globals
->is_casesensitive
);
1490 objectnode
=BE2L(ht
->be_hashentry
[HASHCHAIN(hash16
)]);
1492 while(objectnode
!=0) {
1493 if((errorcode
=findnode(globals
->block_objectnoderoot
, sizeof(struct fsObjectNode
), objectnode
, &cb
, (struct fsNode
**)&on
))!=0) {
1497 nextobjectnode
=BE2L(on
->be_next
);
1499 if(BE2W(on
->be_hash16
)==hash16
) {
1500 if((errorcode
=readcachebuffercheck(&cb
, BE2L(on
->node
.be_data
), OBJECTCONTAINER_ID
))==0) {
1503 if((o
=findobjectbyname((struct fsObjectContainer
*)cb
->data
, name
))!=0) {
1507 if((o
->bits
& OTYPE_LINK
)!=0) {
1508 return(ERROR_IS_SOFT_LINK
);
1515 /* Code below doesn't handle Soft Links correctly. There is a slight chance
1516 that it returns ERROR_IS_SOFT_LINK before knowing that the names really
1519 if((errorcode=readobjectquick(on->node.data,objectnode,&cb,&o))!=0) {
1520 if(errorcode==ERROR_IS_SOFT_LINK) {
1528 if(compareobjectnames(o->name, name)!=FALSE) {
1539 objectnode
=nextobjectnode
;
1542 return(ERROR_OBJECT_NOT_FOUND
);
1546 struct fsObjectContainer
*oc
;
1548 BLCK nextdirblock
=BE2L((*io_o
)->object
.dir
.be_firstdirblock
);
1550 while(nextdirblock
!=0 && (errorcode
=readcachebuffercheck(&cb
, nextdirblock
, OBJECTCONTAINER_ID
))==0) {
1553 if((o
=findobjectbyname(oc
, name
))!=0) {
1557 if((o
->bits
& OTYPE_LINK
)!=0) {
1558 return(ERROR_IS_SOFT_LINK
);
1564 nextdirblock
=BE2L(oc
->be_next
);
1567 if(nextdirblock
==0) {
1568 errorcode
=ERROR_OBJECT_NOT_FOUND
;
1577 LONG
readobject(NODE objectnode
,struct CacheBuffer
**returned_cb
,struct fsObject
**returned_object
) {
1578 struct CacheBuffer
*cb
;
1579 struct fsObjectNode
*on
;
1582 if((errorcode
=findnode(globals
->block_objectnoderoot
, sizeof(struct fsObjectNode
), objectnode
, &cb
, (struct fsNode
**)&on
))==0) {
1583 errorcode
=readobjectquick(BE2L(on
->node
.be_data
),objectnode
,returned_cb
,returned_object
);
1591 LONG
readobjectquick(BLCK objectcontainer
,NODE objectnode
,struct CacheBuffer
**returned_cb
,struct fsObject
**returned_object
) {
1594 if((errorcode
=readcachebuffercheck(returned_cb
,objectcontainer
,OBJECTCONTAINER_ID
))==0) {
1595 struct fsObjectContainer
*oc
=(*returned_cb
)->data
;
1597 if((*returned_object
=findobject(oc
,objectnode
))==0) {
1598 /**** if the system gets here then there was an ObjectNode which didn't point
1599 to a block in which the object exists. This means there MUST be something wrong
1600 with the filesystem or the disk. */
1602 req("ObjectNode %ld points to a block which\ndoesn't contain the intended Object.", "Ok", objectnode
);
1603 errorcode
=ERROR_OBJECT_NOT_FOUND
;
1605 else if(((*returned_object
)->bits
& OTYPE_LINK
)!=0) {
1606 errorcode
=ERROR_IS_SOFT_LINK
;
1615 struct fsObject
*findobject(struct fsObjectContainer
*oc
,NODE objectnode
) {
1616 struct fsObject
*o
=oc
->object
;
1619 endadr
=(UBYTE
*)oc
+globals
->bytes_block
-sizeof(struct fsObject
)-2;
1621 while((UBYTE
*)o
<endadr
&& o
->name
[0]!=0) {
1622 if(BE2L(o
->be_objectnode
)==objectnode
) {
1623 /* a match, which means the correct object was located. */
1634 WORD
objectsize(struct fsObject
*o
) {
1637 /* Returns the exact size of this object in bytes. */
1639 p
=(UBYTE
*)&o
->name
[0];
1641 /* skip the filename */
1645 /* skip the comment */
1649 return((WORD
)(p
-(UBYTE
*)o
));
1654 UBYTE
*getcomment(struct fsObject
*o
) {
1657 p
=(UBYTE
*)&o
->name
[0];
1659 /* skip the filename */
1668 struct fsObject
*lastobject(struct fsObjectContainer
*oc
) {
1669 struct fsObject
*oprev
;
1670 struct fsObject
*o
=oc
->object
;
1672 /* returns the last object. */
1677 } while(isobject(o
, oc
)!=FALSE
);
1684 struct fsObject
*prevobject(struct fsObject
*o
, struct fsObjectContainer
*oc
) {
1685 struct fsObject
*oprev
=0;
1686 struct fsObject
*o2
=oc
->object
;
1688 /* returns the previous object. If there is no previous, zero is returned. */
1693 if(isobject(o2
, oc
)==FALSE
) {
1703 struct fsObject
*nextobject(struct fsObject
*o
) {
1706 /* skips the passed in fsObject and gives a pointer back to the place where
1707 a next fsObject structure could be located */
1709 p
=(UBYTE
*)&o
->name
[0];
1711 /* skip the filename */
1715 /* skip the comment */
1719 /* ensure WORD boundary */
1720 if((((IPTR
)p
) & 0x01)!=0) {
1724 return((struct fsObject
*)p
);
1729 WORD
isobject(struct fsObject
*o
, struct fsObjectContainer
*oc
) {
1732 endadr
=(UBYTE
*)oc
+globals
->bytes_block
-sizeof(struct fsObject
)-2;
1734 if((UBYTE
*)o
<endadr
&& o
->name
[0]!=0) {
1742 static UBYTE
*emptyspaceinobjectcontainer(struct fsObjectContainer
*oc
) {
1743 struct fsObject
*o
=oc
->object
;
1746 /* This function returns a pointer to the first unused byte in
1747 an ObjectContainer. */
1749 endadr
=(UBYTE
*)oc
+globals
->bytes_block
-sizeof(struct fsObject
)-2;
1751 while((UBYTE
*)o
<endadr
&& o
->name
[0]!=0) {
1760 LONG
removeobject(struct CacheBuffer
*cb
, struct fsObject
*o
) {
1761 struct fsObjectContainer
*oc
=cb
->data
;
1764 /* This function removes an object from any directory. It takes care
1765 of delinking the object from the hashchain and also frees the
1768 This function must be called from within a transaction! */
1770 lockcachebuffer(cb
);
1772 if((errorcode
=dehashobjectquick(BE2L(o
->be_objectnode
), o
->name
, BE2L(oc
->be_parent
)))==0) {
1773 NODE objectnode
=BE2L(o
->be_objectnode
);
1775 if((errorcode
=simpleremoveobject(cb
, o
))==0) {
1776 errorcode
=deleteobjectnode(objectnode
);
1780 unlockcachebuffer(cb
);
1790 LONG
renameobject(struct CacheBuffer
*cb
, struct fsObject
*o
, struct ExtFileLock
*lock
, UBYTE
*path
) {
1791 struct CacheBuffer
*cbparent
;
1792 struct fsObject
*oparent
;
1795 /* cb & o is the original object. The lock and path is the new name and location of the object. */
1797 lockcachebuffer(cb
);
1799 if((errorcode
=locatelockableparent(lock
, path
, &cbparent
, &oparent
))==0) {
1800 unlockcachebuffer(cb
);
1801 errorcode
=renameobject2(cb
, o
, cbparent
, oparent
, FilePart(path
), TRUE
);
1804 unlockcachebuffer(cb
);
1812 LONG
renameobject2(struct CacheBuffer
*cb
, struct fsObject
*o
, struct CacheBuffer
*cbparent
, struct fsObject
*oparent
, UBYTE
*newname
, WORD sendnotify
) {
1813 struct fsObjectContainer
*oc
=cb
->data
;
1814 struct fsObject
*oldo
;
1815 UBYTE object
[sizeof(struct fsObject
)+110+80];
1817 UBYTE
*notifypath
=0;
1818 NODE objectnode
=BE2L(o
->be_objectnode
);
1819 NODE sourceparentobjectnode
=BE2L(oc
->be_parent
);
1822 /* The Object indicated by cb & o, gets renamed to newname and placed
1823 in the directory indicated by cbparent & oparent. */
1825 _XDEBUG((DEBUG_OBJECTS
,"renameobject2: Renaming '%s' to '%s' in dir '%s'\n",o
->name
,newname
,oparent
->name
));
1827 oldo
=(struct fsObject
*)object
;
1829 lockcachebuffer(cb
);
1830 lockcachebuffer(cbparent
);
1832 if((o
->bits
& OTYPE_DIR
)!=0 && oc
->be_parent
!=oparent
->be_objectnode
) {
1833 NODE objectnode
=BE2L(o
->be_objectnode
);
1836 struct CacheBuffer
*cb
=cbparent
;
1837 struct fsObject
*o
=oparent
;
1838 struct fsObjectContainer
*oc
;
1840 /* We should check if o isn't a parent of oparent so to avoid renaming
1841 a directory into one of its children. Of course, we only need to
1842 do this when o is a directory, and oparent isn't the parent of o. */
1847 if(objectnode
==BE2L(o
->be_objectnode
)) {
1848 errorcode
=ERROR_OBJECT_IN_USE
;
1852 } while(oc
->be_parent
!=0 && (errorcode
=readobject(BE2L(oc
->be_parent
), &cb
, &o
))==0);
1857 if(sendnotify
!=FALSE
) {
1858 notifypath
=fullpath(cb
,o
);
1861 CopyMem(o
, object
, (UBYTE
*)nextobject(o
)-(UBYTE
*)o
);
1865 /* skip the filename */
1866 while(*comment
++!=0) {
1869 if((errorcode
=dehashobjectquick(objectnode
, o
->name
,BE2L(oc
->be_parent
)))==0) {
1870 ULONG parentobjectnode
=BE2L(oparent
->be_objectnode
);
1872 unlockcachebuffer(cb
);
1874 /* If moving an Object from a directory to a subdirectory of that directory and
1875 the Object is in the same ObjectContainer, then it is possible that oparent
1876 won't point to a valid object anymore after calling simpleremoveobject(). */
1878 if((errorcode
=simpleremoveobject(cb
,o
))==0) {
1879 struct CacheBuffer
*cb
=cbparent
;
1884 o
=findobject((struct fsObjectContainer
*)cb
->data
,parentobjectnode
);
1886 if((oldo
->bits
& OTYPE_DIR
)!=0) {
1888 tag2
=CO_FIRSTDIRBLOCK
;
1890 val1
=BE2L(oldo
->object
.dir
.be_hashtable
);
1891 val2
=BE2L(oldo
->object
.dir
.be_firstdirblock
);
1897 val1
=BE2L(oldo
->object
.file
.be_data
);
1898 val2
=BE2L(oldo
->object
.file
.be_size
);
1901 /* In goes the Parent cb & o, out comes the New object's cb & o :-) */
1903 struct TagItem tags
[] = {
1904 { CO_COMMENT
, (IPTR
)comment
},
1905 { CO_OBJECTNODE
, BE2L(oldo
->be_objectnode
) },
1906 { CO_PROTECTION
, BE2L(oldo
->be_protection
) },
1907 { CO_DATEMODIFIED
, BE2L(oldo
->be_datemodified
) },
1908 { CO_OWNER
, (BE2W(oldo
->be_owneruid
)<<16) + BE2W(oldo
->be_ownergid
) },
1909 { CO_BITS
, oldo
->bits
},
1910 { CO_HASHOBJECT
, TRUE
},
1911 { CO_UPDATEPARENT
, TRUE
},
1917 if((errorcode
=createobjecttagitem(&cb
, &o
, newname
, tags
))==0) {
1919 if((errorcode
=storecachebuffer(cb
))==0 && sendnotify
!=FALSE
) { // Object itself has been completed.
1921 _XDEBUG((DEBUG_OBJECTS
,"renameobject2: Succesfully created & stored new object.\n"));
1923 if(parentobjectnode
!=sourceparentobjectnode
) {
1924 /* Object was moved! */
1925 checknotifyforpath(notifypath
,TRUE
);
1928 /* Object was renamed within same directory */
1929 checknotifyforpath(notifypath
,FALSE
);
1931 checknotifyforobject(cb
,o
,TRUE
); /* fullpath points to a global string so put this notify after the 2 others. */
1937 unlockcachebuffer(cb
);
1941 unlockcachebuffer(cb
);
1944 unlockcachebuffer(cbparent
);
1951 static WORD
changeobjectsize(struct CacheBuffer
*cb
, struct fsObject
*o
, WORD bytes
) {
1952 struct fsObjectContainer
*oc
=cb
->data
;
1953 WORD currentobjectsize
;
1957 /* This function resizes the passed in Object, if possible.
1958 A negative bytes number reduces the size, a positive number
1959 increases the size. This function will return TRUE on
1960 success. newtransaction() must have been called before calling
1963 // currentobjectsize & newobjectsize in bytes:
1965 currentobjectsize
=objectsize(o
);
1966 newobjectsize
=currentobjectsize
+bytes
;
1968 // currentobjectsize & newobjectsize in words:
1970 currentobjectsize
++;
1971 currentobjectsize
>>=1;
1976 words
=newobjectsize
-currentobjectsize
;
1979 preparecachebuffer(cb
);
1989 preparecachebuffer(cb
);
1993 src
=(UWORD
*)o
+ currentobjectsize
;
1996 copywords
=(globals
->bytes_block
>>1)-(src
-(UWORD
*)oc
);
1998 while(--copywords
>=0) {
2006 else if(emptyspaceinobjectcontainer(oc
)-(UBYTE
*)oc
+(words
<<1)<=globals
->bytes_block
) {
2011 preparecachebuffer(cb
);
2013 dst
=(UWORD
*)((UBYTE
*)oc
+globals
->bytes_block
);
2016 copywords
=(globals
->bytes_block
>>1) - (((UWORD
*)o
+ currentobjectsize
+ words
)-(UWORD
*)oc
);
2018 while(--copywords
>=0) {