alsa.audio: move handling of XRUN when writting to the slave task
[AROS.git] / rom / filesys / SFS / FS / locks.c
blob245c6ad83c7b86a4efb2a27cc66880cc1d3fc22b
1 #include "asmsupport.h"
3 #include <dos/dosextens.h>
4 #include <exec/memory.h>
5 #include <exec/types.h>
6 #include <proto/exec.h>
8 #include "locks.h"
9 #include "locks_protos.h"
10 #include "debug.h"
11 #include "fs.h"
12 #include "objects_protos.h"
13 #include "req_protos.h"
14 #include "support_protos.h"
16 #include "globals.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
24 into account */
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;
31 while(lock!=0) {
32 if(lock->objectnode==objectnode) {
33 if(lock->access==EXCLUSIVE_LOCK || accessmode==EXCLUSIVE_LOCK) {
34 return(DOSFALSE);
36 break;
38 lock=lock->next;
41 if(objectnode==globals->templockedobjectnode && accessmode==EXCLUSIVE_LOCK) {
42 return(DOSFALSE);
45 return(DOSTRUE);
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. */
66 if(lock!=0) {
67 if(lock->id==DOSTYPE_ID) {
68 lock->task=0;
70 if(lock->next!=0) {
71 lock->next->prev=lock->prev;
74 if(lock->prev!=0) {
75 lock->prev->next=lock->next;
76 lock->prev->link=TOBADDR(lock->next);
78 else {
80 #if 0
81 // #ifdef STARTDEBUG
83 struct DeviceList *vn=BADDR(lock->volume);
85 if(vn->dl_LockList!=0) {
86 req("Freeing lock!", "Ok");
88 if(lock->next==0) {
89 req("This was the last lock!", "Ok");
93 // #endif
94 #endif
96 #if 0
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"));
102 if(lock->next==0) {
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"));
110 // #ifdef STARTDEBUG
111 // req("Last lock was freed!", "Ok");
112 // #endif
114 if(vn->dl_unused==0) {
115 /* remove the volumenode! */
118 else {
119 vn->dl_LockList=TOBADDR(lock->next);
122 else {
123 locklist=lock->next;
126 #endif
128 globals->locklist=lock->next;
131 if(lock->gh!=0) {
132 freeglobalhandle(lock->gh);
135 FreeMem(lock,sizeof(struct ExtFileLock));
137 else {
138 return(ERROR_INVALID_LOCK);
141 return(0);
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;
179 else {
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;
188 lock->prev=0;
189 if(globals->locklist!=0) {
190 globals->locklist->prev=lock;
192 globals->locklist=lock;
194 lock->id=DOSTYPE_ID;
196 lock->curextent=BE2L(o->object.file.be_data);
198 if((o->bits & (OTYPE_LINK|OTYPE_DIR))==0) {
199 lock->bits=EFL_FILE;
202 *returned_efl=lock;
203 return(0);
205 else {
206 return(ERROR_NO_FREE_STORE);
209 else {
210 return(ERROR_OBJECT_IN_USE);
216 LONG lockobject(struct ExtFileLock *efl, UBYTE *path, LONG accessmode, struct ExtFileLock **returned_efl) {
217 struct CacheBuffer *cb;
218 struct fsObject *o;
219 LONG errorcode;
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
225 exclusively.
227 ERROR_INVALID_LOCK is returned if the lock is not a lock created by this
228 filesystem. */
230 if(efl==0 || efl->id==DOSTYPE_ID) {
231 if((errorcode=locateobjectfromlock(efl, path, &cb, &o))==0) {
232 return(lockobject2(o, accessmode, returned_efl));
234 else {
235 _XDEBUG((DEBUG_LOCK,"lockobject: locateobject failed\n"));
237 return(errorcode);
240 else {
241 return(ERROR_INVALID_LOCK);
247 LONG locateobjectfromlock(struct ExtFileLock *lock, UBYTE *path, struct CacheBuffer **returned_cb, struct fsObject **returned_o) {
248 NODE objectnode;
249 LONG errorcode;
251 if(lock==0) {
252 objectnode=ROOTNODE;
254 else {
255 objectnode=lock->objectnode;
258 if((errorcode=readobject(objectnode, returned_cb, returned_o))==0) {
259 errorcode=locateobject2(&path, returned_cb, returned_o);
262 return(errorcode);
267 LONG locatelockableobject(struct ExtFileLock *lock, UBYTE *path, struct CacheBuffer **returned_cb, struct fsObject **returned_o) {
268 NODE objectnode;
269 LONG errorcode;
271 if(lock==0) {
272 objectnode=ROOTNODE;
274 else {
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;
286 return(errorcode);
291 LONG locateobject(UBYTE *path, struct CacheBuffer **io_cb, struct fsObject **io_o) {
292 UBYTE *p=path;
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;
301 LONG errorcode=0;
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)));
320 while(*path!=0) {
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
327 parsed. */
329 if(*path=='/') {
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;
338 break;
341 if((errorcode=readobject(BE2L(oc->be_parent),io_cb,io_o))!=0) {
342 break;
345 path++;
347 else {
348 /* We've got ourselves an fsObject. */
351 if(((*io_o)->bits & OTYPE_LINK)!=0) {
352 errorcode=ERROR_IS_SOFT_LINK;
353 break;
357 if(((*io_o)->bits & OTYPE_DIR)==0) {
358 _XDEBUG((DEBUG_LOCK,"locateobject: Not a directory\n"));
360 errorcode=ERROR_OBJECT_WRONG_TYPE;
361 break;
364 if((errorcode=scandir(io_cb, io_o, path))!=0) {
365 break;
368 /* We found a piece of the path we were looking for. The fsObject
369 structure returned is the object we are looking for. */
371 while(*path!=0) {
372 if(*path++=='/') {
373 break;
379 *io_path=path;
381 return(errorcode);
386 LONG createglobalhandle(struct ExtFileLock *efl) {
387 struct ExtFileLock *lock;
388 struct CacheBuffer *cb;
389 struct fsObject *o;
390 LONG errorcode;
392 lock=globals->locklist;
394 while(lock!=0) {
395 if(lock->objectnode==efl->objectnode) {
396 if(lock->gh!=0) {
397 efl->gh=lock->gh;
398 lock->gh->count++;
400 // _DEBUG(("createglobalhandle: Returning existing gh structure\n"));
402 return(0);
405 lock=lock->next;
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"));
414 gh->count=1;
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);
423 return(0);
425 else {
426 return(ERROR_NO_FREE_STORE);
430 return(errorcode);
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) {
442 return(gh);
445 gh=(struct GlobalHandle *)(gh->node.mln_Succ);
448 return(0);
453 void freeglobalhandle(struct GlobalHandle *gh) {
454 gh->count--;
455 if(gh->count==0) {
456 removem(&gh->node);
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;
467 while(lock!=0) {
468 if(lock->curextent >= source && lock->curextent < source+blocks) {
469 lock->curextent=0;
470 lock->extentoffset=0;
472 lock=lock->next;
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) {
485 gh->data=dest;
487 gh=(struct GlobalHandle *)(gh->node.mln_Succ);