1 #include "asmsupport.h"
3 #include <dos/dosextens.h>
4 #include <exec/memory.h>
5 #include <exec/types.h>
6 #include <proto/exec.h>
9 #include "locks_protos.h"
12 #include "objects_protos.h"
13 #include "req_protos.h"
14 #include "support_protos.h"
18 void freeglobalhandle(struct GlobalHandle
*gh
);
20 LONG
lockable(NODE objectnode
,LONG accessmode
) {
21 struct ExtFileLock
*lock
;
23 /* returns DOSTRUE if the object passed in is lockable, taking the accessmode
26 /** If looking through the locklist linearly turns out to be slow then
27 this routine may well be enhanced later with a hashing scheme */
29 lock
=globals
->locklist
;
32 if(lock
->objectnode
==objectnode
) {
33 if(lock
->access
==EXCLUSIVE_LOCK
|| accessmode
==EXCLUSIVE_LOCK
) {
41 if(objectnode
==globals
->templockedobjectnode
&& accessmode
==EXCLUSIVE_LOCK
) {
50 void __inline
settemporarylock(NODE objectnode
) {
51 globals
->templockedobjectnode
=objectnode
;
56 void __inline
cleartemporarylock(void) {
57 globals
->templockedobjectnode
=0;
61 LONG
freelock(struct ExtFileLock
*lock
) {
63 /* You may assume that this function never fails for locks
64 temporarily allocated internally. */
67 if(lock
->id
==DOSTYPE_ID
) {
71 lock
->next
->prev
=lock
->prev
;
75 lock
->prev
->next
=lock
->next
;
76 lock
->prev
->link
=TOBADDR(lock
->next
);
83 struct DeviceList
*vn
=BADDR(lock
->volume
);
85 if(vn
->dl_LockList
!=0) {
86 req("Freeing lock!", "Ok");
89 req("This was the last lock!", "Ok");
97 struct DeviceList
*vn
=BADDR(lock
->volume
);
99 if(vn
->dl_LockList
!=0) {
100 _DEBUG(("freelock: Freeing a lock of a volume which isn't currently inserted.\n"));
103 /* Whoops... this was the last lock which was associated with a volume
104 not currently inserted. This means the volumenode's LockList pointer
105 becomes zero if there are still some NotifyRequest's left, or it is
106 completely removed. */
108 _DEBUG(("freelock: This was the last lock associated with that volume!\n"));
111 // req("Last lock was freed!", "Ok");
114 if(vn
->dl_unused
==0) {
115 /* remove the volumenode! */
119 vn
->dl_LockList
=TOBADDR(lock
->next
);
128 globals
->locklist
=lock
->next
;
132 freeglobalhandle(lock
->gh
);
135 FreeMem(lock
,sizeof(struct ExtFileLock
));
138 return(ERROR_INVALID_LOCK
);
145 LONG
lockobject2(struct fsObject
*o
, LONG accessmode
, struct ExtFileLock
**returned_efl
) {
146 struct ExtFileLock
*lock
;
148 /* This function locks the passed object and returns an
149 ExtFileLock structure if successful. */
151 if(BE2L(o
->be_objectnode
)==ROOTNODE
&& accessmode
==EXCLUSIVE_LOCK
) {
152 /* Exclusive locks on the ROOT directory are not allowed */
153 _DEBUG(("lockobject: someone tried to lock the ROOT directory exclusively -- denied\n"));
155 return(ERROR_OBJECT_IN_USE
);
158 /* Below we check if a lock on this object already exists. If a lock
159 already exists and is exclusive then this locking attempt is
160 rejected. If we are requesting an exclusive lock while another
161 lock already exists then the locking attempt is rejected as well. */
163 if(lockable(BE2L(o
->be_objectnode
), accessmode
)!=DOSFALSE
) {
165 _XDEBUG((DEBUG_LOCK
,"lockobject: lockable returned TRUE\n"));
167 /* If we got this far then we can safely create the requested lock and
168 add it to the locklist. */
170 if((lock
=AllocMem(sizeof(struct ExtFileLock
), MEMF_PUBLIC
|MEMF_CLEAR
))!=0) {
171 lock
->objectnode
=BE2L(o
->be_objectnode
);
173 /* accessmode is not simply copied because some apps think anything which isn't
174 an exclusive lock is a shared lock. */
176 if(accessmode
==EXCLUSIVE_LOCK
) {
177 lock
->access
=EXCLUSIVE_LOCK
;
180 lock
->access
=SHARED_LOCK
;
183 lock
->task
=&globals
->mytask
->pr_MsgPort
;
184 lock
->volume
=TOBADDR(globals
->volumenode
);
186 lock
->link
=TOBADDR(globals
->locklist
);
187 lock
->next
=globals
->locklist
;
189 if(globals
->locklist
!=0) {
190 globals
->locklist
->prev
=lock
;
192 globals
->locklist
=lock
;
196 lock
->curextent
=BE2L(o
->object
.file
.be_data
);
198 if((o
->bits
& (OTYPE_LINK
|OTYPE_DIR
))==0) {
206 return(ERROR_NO_FREE_STORE
);
210 return(ERROR_OBJECT_IN_USE
);
216 LONG
lockobject(struct ExtFileLock
*efl
, UBYTE
*path
, LONG accessmode
, struct ExtFileLock
**returned_efl
) {
217 struct CacheBuffer
*cb
;
221 /* Creates a new ExtFileLock if possible.
223 ERROR_OBJECT_IN_USE is returned if an exclusive lock is present on the object
224 to be locked, or if a shared lock is present while you're trying to lock it
227 ERROR_INVALID_LOCK is returned if the lock is not a lock created by this
230 if(efl
==0 || efl
->id
==DOSTYPE_ID
) {
231 if((errorcode
=locateobjectfromlock(efl
, path
, &cb
, &o
))==0) {
232 return(lockobject2(o
, accessmode
, returned_efl
));
235 _XDEBUG((DEBUG_LOCK
,"lockobject: locateobject failed\n"));
241 return(ERROR_INVALID_LOCK
);
247 LONG
locateobjectfromlock(struct ExtFileLock
*lock
, UBYTE
*path
, struct CacheBuffer
**returned_cb
, struct fsObject
**returned_o
) {
255 objectnode
=lock
->objectnode
;
258 if((errorcode
=readobject(objectnode
, returned_cb
, returned_o
))==0) {
259 errorcode
=locateobject2(&path
, returned_cb
, returned_o
);
267 LONG
locatelockableobject(struct ExtFileLock
*lock
, UBYTE
*path
, struct CacheBuffer
**returned_cb
, struct fsObject
**returned_o
) {
275 objectnode
=lock
->objectnode
;
278 if((errorcode
=readobject(objectnode
, returned_cb
, returned_o
))==0) {
279 if((errorcode
=locateobject2(&path
, returned_cb
, returned_o
))==0) {
280 if(objectnode
!=BE2L((*returned_o
)->be_objectnode
) && lockable(BE2L((*returned_o
)->be_objectnode
), SHARED_LOCK
)==DOSFALSE
) {
281 errorcode
=ERROR_OBJECT_IN_USE
;
291 LONG
locateobject(UBYTE
*path
, struct CacheBuffer
**io_cb
, struct fsObject
**io_o
) {
294 return(locateobject2(&p
, io_cb
, io_o
));
299 LONG
locateobject2(UBYTE
**io_path
, struct CacheBuffer
**io_cb
, struct fsObject
**io_o
) {
300 UBYTE
*path
=*io_path
;
303 /* Path is a normal C string. It may include a colon. Everything up to the
304 last colon found in the string (if any) will be ignored.
306 This function parses the path passed in and locates the object it refers
307 to relative to the passed in object.
308 This function returns an AmigaDOS errorcode in case of a problem, or zero
309 if everything went okay.
311 ERROR_OBJECT_WRONG_TYPE will be returned if a file is accidentally
312 referred to as a directory.
314 ERROR_OBJECT_NOT_FOUND will be returned if we can't find the object. */
316 path
=stripcolon(path
);
318 _XDEBUG((DEBUG_LOCK
,"locateobject: Locating object with path '%s' from ObjectNode %ld\n",path
,BE2L((*io_o
)->be_objectnode
)));
322 /* We've got an Object which is the start of the path which still needs to
323 be parsed. If the path starts with a slash we get the parent block and
324 remove the slash from the path. If the path doesn't start with a slash
325 we scan the directory for the Object which that part of the path
326 indicates. We continue this process until the entire path has been
330 struct fsObjectContainer
*oc
=(*io_cb
)->data
;
332 if(BE2L(oc
->be_parent
)==0) {
333 /* We can't get the parent of the root! */
335 _XDEBUG((DEBUG_LOCK
,"locateobject: Can't get parent of the root\n"));
337 errorcode
=ERROR_OBJECT_NOT_FOUND
;
341 if((errorcode
=readobject(BE2L(oc
->be_parent
),io_cb
,io_o
))!=0) {
348 /* We've got ourselves an fsObject. */
351 if(((*io_o)->bits & OTYPE_LINK)!=0) {
352 errorcode=ERROR_IS_SOFT_LINK;
357 if(((*io_o
)->bits
& OTYPE_DIR
)==0) {
358 _XDEBUG((DEBUG_LOCK
,"locateobject: Not a directory\n"));
360 errorcode
=ERROR_OBJECT_WRONG_TYPE
;
364 if((errorcode
=scandir(io_cb
, io_o
, path
))!=0) {
368 /* We found a piece of the path we were looking for. The fsObject
369 structure returned is the object we are looking for. */
386 LONG
createglobalhandle(struct ExtFileLock
*efl
) {
387 struct ExtFileLock
*lock
;
388 struct CacheBuffer
*cb
;
392 lock
=globals
->locklist
;
395 if(lock
->objectnode
==efl
->objectnode
) {
400 // _DEBUG(("createglobalhandle: Returning existing gh structure\n"));
408 if((errorcode
=readobject(efl
->objectnode
, &cb
, &o
))==0) {
409 if((efl
->gh
=AllocMem(sizeof(struct GlobalHandle
), MEMF_PUBLIC
))!=0) {
410 struct GlobalHandle
*gh
=efl
->gh
;
412 // _DEBUG(("createglobalhandle: Allocated new gh structure\n"));
416 gh
->objectnode
=efl
->objectnode
;
417 gh
->size
=BE2L(o
->object
.file
.be_size
);
418 gh
->protection
=BE2L(o
->be_protection
);
419 gh
->data
=BE2L(o
->object
.file
.be_data
);
421 addtailm(&globals
->globalhandles
,&gh
->node
);
426 return(ERROR_NO_FREE_STORE
);
435 struct GlobalHandle
*findglobalhandle(NODE objectnode
) {
436 struct GlobalHandle
*gh
;
438 gh
=(struct GlobalHandle
*)globals
->globalhandles
.mlh_Head
;
440 while(gh
->node
.mln_Succ
!=0) {
441 if(gh
->objectnode
==objectnode
) {
445 gh
=(struct GlobalHandle
*)(gh
->node
.mln_Succ
);
453 void freeglobalhandle(struct GlobalHandle
*gh
) {
457 FreeMem(gh
,sizeof(struct GlobalHandle
));
463 void updatelocksaftermove(BLCK source
, BLCK dest
, ULONG blocks
) {
464 struct ExtFileLock
*lock
=globals
->locklist
;
465 struct GlobalHandle
*gh
;
468 if(lock
->curextent
>= source
&& lock
->curextent
< source
+blocks
) {
470 lock
->extentoffset
=0;
475 /* The FirstDataBlock pointer in a GlobalHandle might need to be
476 changed. Because this is the first extent of a file, it cannot
477 be merged with a previous extent. This means that /source/ must
478 equal the FirstDataBlock number exactly, and that /dest/ is
479 always the new location. */
481 gh
=(struct GlobalHandle
*)globals
->globalhandles
.mlh_Head
;
483 while(gh
->node
.mln_Succ
!=0) {
484 if(gh
->data
==source
) {
487 gh
=(struct GlobalHandle
*)(gh
->node
.mln_Succ
);