3 * Revision 11.4 1999/02/22 16:33:43 Michiel
4 * Changes for increasing deldir capacity
6 * Revision 11.3 1995/12/21 12:05:55 Michiel
7 * bugfix: anodechain wasn't freed after closing file
9 * Revision 11.2 1995/12/07 15:25:38 Michiel
10 * rollover support and bugfixes
12 * Revision 11.1 1995/10/03 11:19:27 Michiel
13 * merged develop: anodechain
15 * Revision 10.15 1995/08/04 11:51:19 Michiel
16 * Some memory-allocation fail conditions tests added
18 * Revision 10.14 1995/07/21 06:54:46 Michiel
19 * MakeListEntry() adapted for DELDIR
21 * Revision 10.13 1995/07/18 06:56:13 Michiel
22 * changed multiuser access functions
24 * Revision 10.12 1995/06/15 18:56:53 Michiel
27 * Revision 10.11 1995/06/07 19:17:19 Michiel
28 * added multiuser routines
30 * Revision 10.10 1995/06/04 06:04:31 Michiel
33 * Revision 10.9 1995/03/24 16:31:07 Michiel
34 * MakeListEntry adapted for soflinks & bugfixed
36 * Revision 10.8 1995/02/28 18:26:58 Michiel
37 * MakeListEntry resolves links now
39 * Revision 10.7 1995/02/15 16:43:39 Michiel
41 * Using new headers (struct.h & blocks.h)
43 * Revision 10.6 1995/01/18 04:29:34 Michiel
44 * Bugfixes. Now ready for beta release.
46 * Revision 10.5 1994/11/15 17:52:30 Michiel
49 * Revision 10.4 1994/10/29 08:55:03 Michiel
50 * changed process references to msgport references
52 * Revision 10.3 1994/10/28 06:06:40 Michiel
53 * use new listentry field 'anodenr'
54 * this was essential for AccessConflict()
56 * Revision 10.1 1994/10/24 11:16:28 Michiel
68 #include "lock_protos.h"
69 #include "directory_protos.h"
70 #include "volume_protos.h"
71 #include "anodes_protos.h"
72 #include "disk_protos.h"
74 /**********************************************************************/
76 /**********************************************************************/
80 static UBYTE debugbuf
[120];
81 #define DebugOn debug++
82 #define DebugOff debug=(debug?debug-1:0)
83 #define DebugMsg(msg) if(debug) {NormalErrorMsg(msg, NULL); debug=0;}
84 #define DebugMsgNum(msg, num) sprintf(debugbuf, "%s 0x%08lx.", msg, num); \
85 if(debug) {NormalErrorMsg(debugbuf, NULL); debug=0;}
86 #define DebugMsgName(msg, name) sprintf(debugbuf, "%s >%s<.", msg, name); \
87 if(debug) {NormalErrorMsg(debugbuf, NULL); debug=0;}
92 #define DebugMsgNum(msg,num)
93 #define DebugMsgName(msg, name)
96 /**********************************************************************/
97 /* MAKE/REMOVE/FREE */
98 /* MAKE/REMOVE/FREE */
99 /* MAKE/REMOVE/FREE */
100 /**********************************************************************/
104 ** Allocated filentry structure and fill it with data from objectinfo and
105 ** listtype. The result should be freed with FreeListEntry.
107 ** input : - info: objectinfo of object
108 ** - type: desired type (readlock, writelock, readfe, writefe)
110 ** result: the fileentry, or NULL if failure
112 struct listentry
*MakeListEntry (union objectinfo
*info
, listtype type
, SIPTR
*error
, globaldata
*g
)
114 listentry_t
*listentry
;
115 union objectinfo newinfo
;
117 struct extrafields extrafields
;
119 struct deldirentry
*dde
= 0;
122 ENTER("MakeListEntry");
124 // alloceren fileentry
125 switch (type
.flags
.type
)
127 case ETF_FILEENTRY
: size
= sizeof(fileentry_t
); break;
129 case ETF_LOCK
: size
= sizeof(lockentry_t
); break;
130 default: listentry
= NULL
; return listentry
;
133 DB(Trace(1,"MakeListEntry","size = %lx\n",size
));
136 if (IsDelDir(*info
) || IsVolume(*info
) || IsDir(*info
))
138 if (IsVolume(*info
) || IsDir(*info
))
142 /* softlinks cannot directly be opened */
144 if (info
->deldir
.special
> SPECIAL_DELFILE
&& info
->file
.direntry
->type
== ST_SOFTLINK
)
146 if (!IsVolume(*info
) && info
->file
.direntry
->type
== ST_SOFTLINK
)
149 *error
= ERROR_IS_SOFT_LINK
;
153 if (!(listentry
= AllocMemP (size
, g
)))
155 *error
= ERROR_NO_FREE_STORE
;
159 /* go after link and fetch the fileinfo of the real object
160 * (stored in 'newinfo'
163 if (info
->deldir
.special
> SPECIAL_DELFILE
&& (
165 if (!IsVolume(*info
) && (
167 (info
->file
.direntry
->type
== ST_LINKFILE
) ||
168 (info
->file
.direntry
->type
== ST_LINKDIR
)))
170 struct canode linknode
;
172 /* The clustersize of the linknode (direntry.anode)
173 * actually is the anodenr of the directory the linked to
174 * object is in. The object can be found by searching for
175 * 'anode == objectid'. This objectid can be found in
178 GetExtraFields(info
->file
.direntry
, &extrafields
);
179 GetAnode(&linknode
, info
->file
.direntry
->anode
, g
);
180 if (!FetchObject(linknode
.clustersize
, extrafields
.link
, &newinfo
, g
))
182 *error
= ERROR_OBJECT_NOT_FOUND
;
192 listentry
->type
= type
;
194 switch (newinfo
.delfile
.special
)
197 listentry
->anodenr
= ANODE_ROOTDIR
; break;
200 listentry
->anodenr
= 0; break;
202 case SPECIAL_DELFILE
:
203 dde
= GetDeldirEntryQuick(newinfo
.delfile
.slotnr
, g
);
204 listentry
->anodenr
= dde
->anodenr
;
208 listentry
->anodenr
= newinfo
.file
.direntry
->anode
; break;
211 listentry
->anodenr
= (newinfo
.file
.direntry
) ? (newinfo
.file
.direntry
->anode
) : ANODE_ROOTDIR
;
214 listentry
->info
= newinfo
;
215 listentry
->lock
.fl_Access
= (type
.flags
.access
& 2) ? EXCLUSIVE_LOCK
: SHARED_LOCK
;
216 listentry
->lock
.fl_Task
= g
->msgport
;
217 listentry
->lock
.fl_Volume
= MKBADDR(g
->currentvolume
->devlist
);
218 listentry
->volume
= g
->currentvolume
;
221 switch (type
.flags
.type
)
224 listentry
->lock
.fl_Key
= 0;
225 // listentry->lock.fl_Volume = MKBADDR(newinfo.volume.volume->devlist);
226 // listentry->volume = newinfo.volume.volume;
230 /* every dirlock MUST have a different fl_Key (DOPUS!) */
231 listentry
->lock
.fl_Key
= listentry
->anodenr
;
232 // listentry->lock.fl_Volume = MKBADDR(newinfo.file.dirblock->volume->devlist);
233 // listentry->volume = newinfo.file.dirblock->volume;
237 #define fe ((fileentry_t *)listentry)
238 listentry
->lock
.fl_Key
= listentry
->anodenr
;
239 // listentry->lock.fl_Volume = MKBADDR(MKBADDR(newinfo.file.dirblock->volume->devlist);
240 // listentry->volume = newinfo.file.dirblock->volume;
241 fe
->originalsize
= IsDelFile(newinfo
) ? GetDDFileSize(dde
, g
) :
242 GetDEFileSize(newinfo
.file
.direntry
, g
);
244 /* Get anodechain. If it fails anodechain will become NULL. This has to be
245 * taken into account by functions that use the chain
247 fe
->anodechain
= GetAnodeChain (listentry
->anodenr
, g
);
248 fe
->currnode
= &fe
->anodechain
->head
;
251 /* Rollover file: set offset to rollfileoffset */
252 /* check for rollover files */
253 if (IsRollover(newinfo
))
255 GetExtraFields(newinfo
.file
.direntry
, &extrafields
);
256 SeekInFile(fe
,extrafields
.rollpointer
,OFFSET_BEGINNING
,error
,g
);
258 #endif /* ROLLOVER */
273 ** Checks if the listentry causes access conflicts
274 ** Adds the entry to the locklist
276 BOOL
_AddListEntry (listentry_t
*entry
, globaldata
*g
)
278 struct volumedata
*volume
;
280 DB(Trace(1,"AddListEntry","fe = %lx\n", entry
->volume
->fileentries
.mlh_Head
));
285 if (AccessConflict(entry
))
287 DB(Trace(1,"AddListEntry","found accessconflict!"));
291 volume
= entry
->volume
;
293 /* add to head of list; als link locks using BPTRs */
294 if (!IsMinListEmpty(&volume
->fileentries
))
295 entry
->lock
.fl_Link
= MKBADDR(&(((listentry_t
*)HeadOf(&volume
->fileentries
))->lock
));
297 entry
->lock
.fl_Link
= BNULL
;
299 MinAddHead (&volume
->fileentries
, entry
);
306 ** removes 'entry' from the list and frees entry with FreeFileEntry
308 ** also think about empty lists: kill volume if empty and not present
309 ** also makes lock-links
311 void RemoveListEntry (listentry_t
*entry
, globaldata
*g
)
313 struct volumedata
*volume
;
314 struct MinList
*previous
;
317 volume
= entry
->volume
;
319 /* remove from list */
322 /* update FileLock link */
323 previous
= (struct MinList
*)entry
->prev
;
327 ((listentry_t
*)previous
)->lock
.fl_Link
=
328 MKBADDR(&(((listentry_t
*)entry
)->next
->lock
));
330 ((listentry_t
*)previous
)->lock
.fl_Link
= BNULL
;
332 entry
->lock
.fl_Task
= NULL
;
333 FreeListEntry (entry
, g
);
335 if (g
->currentvolume
!= volume
)
337 /* check if last lock; yes:kill (only if not current disk)
339 if (IsMinListEmpty (&volume
->fileentries
))
341 DB(Trace(1,"RemoveListEntry", "killing volumedata\n"));
343 // LockDosList (LDF_VOLUMES|LDF_READ);
345 RemDosEntry ((struct DosList
*)volume
->devlist
);
346 FreeDosEntry ((struct DosList
*)volume
->devlist
);
347 FreeVolumeResources (volume
, g
);
348 // UnLockDosList (LDF_VOLUMES|LDF_READ);
351 /* update doslist->dl_LockList if necessary
353 else if (previous
== (struct MinList
*)&volume
->fileentries
)
355 // LockDosList (LDF_VOLUMES|LDF_READ);
357 volume
->devlist
->dl_LockList
= MKBADDR(&(((fileentry_t
*)HeadOf(&volume
->fileentries
))->le
.lock
));
358 // UnLockDosList (LDF_VOLUMES|LDF_READ);
364 void FreeListEntry(listentry_t
*entry
, globaldata
*g
)
366 #define fe ((fileentry_t *)entry)
367 if (IsFileEntry(entry
) && fe
->anodechain
)
368 DetachAnodeChain(fe
->anodechain
, g
);
373 /**********************************************************************/
377 /**********************************************************************/
379 BOOL
_ChangeAccessMode(listentry_t
*file
, LONG mode
, SIPTR
*error
, globaldata
*g
)
381 UWORD oldmode
, newmode
;
383 // -I- make dosmode compatible with listtype-mode
390 newmode
= ET_EXCLWRITE
; break;
394 newmode
= ET_SHAREDREAD
; break;
397 // -II- check if mode is already correct
398 oldmode
= file
->type
.flags
.access
;
399 if (oldmode
== newmode
)
402 // -III- operation always ok if oldmode exclusive or newmode shared
403 if (oldmode
>1 || newmode
<=1)
405 file
->type
.flags
.access
= newmode
;
406 file
->lock
.fl_Access
= (newmode
> 1) ? EXCLUSIVE_LOCK
: SHARED_LOCK
;
410 // -IV- otherwise: check for accessconflict
411 MinRemove(file
); // prevents access conflict on itself
412 file
->type
.flags
.access
= newmode
;
413 file
->lock
.fl_Access
= (newmode
> 1) ? EXCLUSIVE_LOCK
: SHARED_LOCK
;
414 if (!AccessConflict(file
))
416 MinAddHead(&file
->volume
->fileentries
, file
);
421 file
->type
.flags
.access
= oldmode
;
422 file
->lock
.fl_Access
= (oldmode
> 1) ? EXCLUSIVE_LOCK
: SHARED_LOCK
;
423 MinAddHead(&file
->volume
->fileentries
, file
);
424 *error
= ERROR_OBJECT_IN_USE
;
429 /**********************************************************************/
433 /**********************************************************************/
437 ** input : - [entry]: the object to be granted access
438 ** This object should contain valid references
440 ** result: TRUE = accessconflict; FALSE = no accessconflict
441 ** All locks on same ANODE are checked. So a lock on a link can
442 ** be denied if the linked to file is locked exclusively.
444 ** Because UpdateReference always updates all references to a dirblock,
445 ** and the match object is valid, a flushed reference CANNOT point to
446 ** the same dirblock. If it is a link, it CAN reference the same
449 ** Returns FALSE if there is an exclusive lock or if there is
450 ** write access on a shared lock
453 BOOL
AccessConflict (listentry_t
*entry
)
457 struct volumedata
*volume
;
459 DB(Trace(1,"Accessconflict","entry %lx\n",entry
));
462 anodenr
= entry
->anodenr
;
463 volume
= entry
->volume
;
465 // -II- zoek locks naar zelfde object
466 for(fe
= HeadOf(&volume
->fileentries
); fe
->next
; fe
=fe
->next
)
468 if(fe
->type
.flags
.type
== ETF_VOLUME
)
470 if(entry
->type
.flags
.type
== ETF_VOLUME
&&
471 (!SHAREDLOCK(fe
->type
) || !SHAREDLOCK(entry
->type
)))
473 DB(Trace(1,"Accessconflict","on volume\n"));
477 else if(fe
->anodenr
== anodenr
)
479 // on of the two wants or has an exclusive lock?
480 if(!SHAREDLOCK(fe
->type
) || !SHAREDLOCK(entry
->type
))
482 DB(Trace(1,"Accessconflict","exclusive lock\n"));
486 // new & old shared lock, both write?
487 else if(fe
->type
.flags
.access
== ET_SHAREDWRITE
&&
488 entry
->type
.flags
.access
== ET_SHAREDWRITE
)
490 DB(Trace(1,"Accessconflict","two write locks\n"));
496 return FALSE
; // no conflicting locks
501 * checks <list> for a lock on the file with anode anodenr
502 * ONLY FOR LOCKS TO CURRENTVOLUME
504 BOOL
ScanLockList (listentry_t
*list
, ULONG anodenr
)
506 for (;list
->next
; list
=list
->next
)
508 if (list
->anodenr
== anodenr
)
517 /*****************************************************************************/
519 /*****************************************************************************/
522 * Check if access allowed
523 * protection is the LW protection of the object
524 * flags are flags of GetRelationshipA
528 ULONG
muFS_CheckReadAccess (ULONG protection
, ULONG flags
, globaldata
*g
)
530 if (flags
& (muRelF_UID_MATCH
| muRelF_NO_OWNER
))
532 if (protection
& FIBF_READ
)
533 return ERROR_READ_PROTECTED
;
535 else if (flags
& (muRelF_GID_MATCH
))
537 if (!(protection
& FIBF_GRP_READ
))
538 return ERROR_READ_PROTECTED
;
540 else if (!(protection
& FIBF_OTR_READ
))
541 return ERROR_READ_PROTECTED
;
546 ULONG
muFS_CheckWriteAccess (ULONG protection
, ULONG flags
, globaldata
*g
)
548 if (flags
& (muRelF_UID_MATCH
| muRelF_NO_OWNER
))
550 if (protection
& FIBF_WRITE
)
551 return ERROR_WRITE_PROTECTED
;
553 else if (flags
& (muRelF_GID_MATCH
))
555 if (!(protection
& FIBF_GRP_WRITE
))
556 return ERROR_WRITE_PROTECTED
;
558 else if (!(protection
& FIBF_OTR_WRITE
))
559 return ERROR_WRITE_PROTECTED
;
564 ULONG
muFS_CheckDeleteAccess (ULONG protection
, ULONG flags
, globaldata
*g
)
566 if (flags
& (muRelF_UID_MATCH
| muRelF_NO_OWNER
))
568 if (protection
& FIBF_DELETE
)
569 return ERROR_DELETE_PROTECTED
;
571 else if (flags
& (muRelF_GID_MATCH
))
573 if (!(protection
& FIBF_GRP_DELETE
))
574 return ERROR_DELETE_PROTECTED
;
576 else if (!(protection
& FIBF_OTR_DELETE
))
577 return ERROR_DELETE_PROTECTED
;