2 /* $Log: dd_support.c $
3 * Revision 1.9 1999/02/22 16:33:43 Michiel
4 * Changes for increasing deldir capacity
6 * Revision 1.8 1998/09/27 11:26:37 Michiel
9 * Revision 1.7 1997/03/03 22:04:04 Michiel
12 * Revision 1.6 1996/03/29 17:02:54 Michiel
13 * update sleeproutines
15 * Revision 1.5 1996/01/30 12:49:23 Michiel
16 * --- working tree overlap ---
20 /**********************
24 static BOOL
RenameDisk(UBYTE
*, globaldata
*);
26 static void NotifyUser(struct NotifyRequest
*nr
, globaldata
*g
);
27 static struct notifyobject
*CheckNotify(ULONG parentanodenr
, DSTR objectname
,
28 struct notifyobject
*no
, BOOL checkparent
, globaldata
*);
29 void PFSDoNotify(struct fileinfo
*object
, BOOL checkparent
, globaldata
*g
);
30 void PFSUpdateNotify(ULONG dirnode
, DSTR filename
, ULONG anodenr
, globaldata
*g
);
34 static void Sleep (globaldata
*g
);
35 static void Awake (globaldata
*g
);
36 static void Alarm (globaldata
*g
);
37 static LONG
UpdateAnode (ULONG old
, ULONG
new, globaldata
*g
);
38 void HandleSleepMsg (globaldata
*g
);
41 /**********************
45 #define SkipColon(filename,pathname) \
47 if ((filename = strchr ((pathname), ':'))) \
50 filename=(pathname); \
53 #define LocateFile(parentfi,filename,objectfi,error) \
55 if (!FindObject (parentfi, filename, &(objectfi), error, g)) \
58 if (IsVolume(objectfi)) \
60 *error = ERROR_OBJECT_WRONG_TYPE; \
66 #define muGetRelationship(extrafields) \
68 (muGetRelationshipA (g->user, ((extrafields).uid << 16) + (extrafields).gid, NULL)) : \
69 ((((extrafields).uid == muNOBODY_UID) << muRelB_NO_OWNER) | muRelF_NOBODY))
72 #define CheckPropertyAccess(objectfi,extrafields,flags, error) \
74 GetExtraFieldsOI (&(objectfi), &(extrafields), g); \
76 flags = muGetRelationshipA (g->user, ((extrafields).uid << 16) + (extrafields).gid, NULL); \
78 flags = (((extrafields).uid == muNOBODY_UID) << muRelB_NO_OWNER) | muRelF_NOBODY; \
80 if (!(flags & muRel_PROPERTY_ACCESS)) \
82 *error = ERROR_WRITE_PROTECTED; \
87 #define CheckPropertyAccess(objectfi,extrafields,flags, error) \
89 GetExtraFields ((objectfi).file.direntry, &(extrafields)); \
91 flags = muGetRelationshipA (g->user, ((extrafields).uid << 16) + (extrafields).gid, NULL); \
93 flags = (((extrafields).uid == muNOBODY_UID) << muRelB_NO_OWNER) | muRelF_NOBODY; \
95 if (!(flags & muRel_PROPERTY_ACCESS)) \
97 *error = ERROR_WRITE_PROTECTED; \
103 #else /* MULTIUSER */
104 #define muGetRelationship(extrafields)
105 #define CheckPropertyAccess(objectfi,extrafields,flags,error)
106 #endif /* MULTIUSER */
109 * BPTR, BOOL, listentry_t *, union objectinfo *
111 #define GetFileInfoFromLock(argument, access, fe, fi) \
113 if ((fe = LockEntryFromLock (argument))) \
115 if (!CheckVolume ((fe)->le.volume, access, error, g)) \
117 UpdateLE ((listentry_t *)(fe), g); \
118 fi = &(fe)->le.info; \
122 if (!g->currentvolume) \
124 *error = ERROR_NO_DISK; \
133 /**********************
137 static BOOL
RenameDisk (UBYTE
*newname
, globaldata
*g
) //%4.5
140 struct volumedata
*volume
= g
->currentvolume
;
144 if (g
->currentvolume
&& (strlen(newname
) < DNSIZE
))
146 /* Write changes directly to disk to prevent disk recognition problems.
147 * (So DON'T use updatedisk)
149 diskname
= volume
->rootblk
->diskname
;
150 *diskname
= strlen(newname
);
151 CopyMem (newname
, diskname
+1, strlen(newname
));
152 RawWrite ((UBYTE
*)volume
->rootblk
, 1, ROOTBLOCK
, g
); /* %7.2 */
153 g
->request
->iotd_Req
.io_Command
= CMD_UPDATE
;
154 DoIO ((struct IORequest
*)g
->request
);
155 volume
->rootblockchangeflag
= FALSE
;
165 /**********************
169 static void NotifyUser (struct NotifyRequest
*nr
, globaldata
*g
)
171 struct NotifyMessage
*msg
;
173 if (nr
->nr_MsgCount
&& (nr
->nr_Flags
& NRF_WAIT_REPLY
))
175 nr
->nr_Flags
|= NRF_MAGIC
;
179 if (nr
->nr_Flags
& NRF_SEND_MESSAGE
)
181 if (!(msg
= AllocMemP (sizeof(struct NotifyMessage
), g
)))
184 msg
->nm_ExecMessage
.mn_ReplyPort
= g
->notifyport
;
185 msg
->nm_ExecMessage
.mn_Length
= sizeof(struct NotifyMessage
);
186 msg
->nm_Class
= NOTIFY_CLASS
;
187 msg
->nm_Code
= NOTIFY_CODE
;
189 PutMsg (nr
->nr_stuff
.nr_Msg
.nr_Port
, &msg
->nm_ExecMessage
);
192 else if (nr
->nr_Flags
& NRF_SEND_SIGNAL
)
194 Signal (nr
->nr_stuff
.nr_Signal
.nr_Task
, 1<<nr
->nr_stuff
.nr_Signal
.nr_SignalNum
);
199 * Checks if there is a notify for the object identified by anodenr
201 static struct notifyobject
*
202 CheckNotify (ULONG parentanodenr
, DSTR objectname
, struct notifyobject
*no
,
203 BOOL checkparent
, globaldata
*g
)
206 no
= HeadOf(&g
->currentvolume
->notifylist
);
210 for ( ; no
->next
; no
=no
->next
)
213 if (no
->parentanodenr
== parentanodenr
)
215 if (intlcmp(no
->objectname
, objectname
))
220 if (checkparent
&& no
->anodenr
== parentanodenr
)
228 * Notifies change of object & dir object is in
230 void PFSDoNotify (struct fileinfo
*object
, BOOL checkparent
, globaldata
*g
)
232 struct notifyobject
*no
= NULL
;
235 if ((IPTR
)object
->direntry
<= SPECIAL_DELFILE
)
239 while ((no
= CheckNotify (object
->dirblock
->blk
.anodenr
,
240 (DSTR
)&object
->direntry
->nlength
, no
, checkparent
, g
)))
241 NotifyUser(no
->req
, g
);
246 * To be called when a object named filename is created in dir
247 * dirnode. This routine checks if there is a partially parsed
248 * notify request in that directory that matches the newly
249 * created object. If so, the parsing of the notify request
252 void PFSUpdateNotify (ULONG dirnode
, DSTR filename
, ULONG anodenr
, globaldata
*g
)
254 struct notifyobject
*no
= NULL
;
257 for (no
= HeadOf(&g
->currentvolume
->notifylist
); no
->next
; no
=no
->next
)
259 /* check for parsed path match */
260 if (no
->parentanodenr
== dirnode
)
264 /* check if we can continue parsing */
265 temp
= strchr(no
->unparsed
, '/');
269 if (intlcdcmp(no
->unparsed
, filename
))
272 no
->unparsed
= *(temp
+1) ? (temp
+1) : NULL
;
276 no
->parentanodenr
= anodenr
;
284 /* check if new object is a notify object */
285 if (intlcmp(no
->objectname
, filename
))
287 no
->anodenr
= anodenr
;
295 /**********************
303 * All direct directory block references are replaced by an
304 * anode reference. The reference can later be restored by
305 * searching the object in the directory identified by the
308 * Examine chains have to be broken since sleepwalkers are
309 * allowed to change directory order
311 static void Sleep (globaldata
*g
)
314 struct volumedata
*volume
= g
->currentvolume
;
318 /* first update disk */
321 /* flush references */
322 for (le
=HeadOf (&volume
->fileentries
); le
->next
; le
=le
->next
)
324 if (!IsVolumeEntry(le
))
326 /* load flushed references */
328 LoadDirBlock (le
->dirblocknr
, g
);
330 le
->diranodenr
= le
->info
.file
.dirblock
->blk
.anodenr
;
335 fileentry_t
*fe
= (fileentry_t
*)le
;
338 DetachAnodeChain (fe
->anodechain
, g
);
344 /* now kill all flushed references (they are now replaced
345 * by anode references in le->diranodenr)
347 for (le
=HeadOf (&volume
->fileentries
); le
->next
; le
=le
->next
)
351 /* terminate examine chains */
352 if (le
->type
.flags
.dir
&& !IsDelDir(le
->info
))
354 ((lockentry_t
*)le
)->nextentry
.direntry
= NULL
;
355 ((lockentry_t
*)le
)->nextentry
.dirblock
= NULL
;
356 ((lockentry_t
*)le
)->nextdirblocknr
= 0;
357 ((lockentry_t
*)le
)->nextdirblockoffset
= 0;
362 /* flush cache. Watch it: FreeUnusedResources also calls
363 * the conventional FlushBlock!
365 FreeUnusedResources (volume
, g
);
371 /* enter sleepmode */
372 g
->DoCommand
= SleepCommands
;
378 * Reload all essential blocks. References are restored by searching
379 * by anodenr in the directory identified by diranodenr (using FetchObject)
381 static void Awake (globaldata
*g
)
384 struct volumedata
*volume
= g
->currentvolume
;
385 struct rootblock
*rootblock
;
390 /* reload current rootblock */
391 rootblock
= volume
->rootblk
;
392 RawRead((UBYTE
*)rootblock
, rootblock
->rblkcluster
, ROOTBLOCK
, g
);
394 /* reload rootblock extension */
395 if (rootblock
->extension
&& (rootblock
->options
& MODE_EXTENSION
))
396 RawRead((UBYTE
*)&volume
->rblkextension
->blk
, volume
->rescluster
,
397 rootblock
->extension
, g
);
400 // if (rootblock->deldir && (rootblock->options & MODE_DELDIR))
401 // RawRead((UBYTE *)&volume->deldir->blk, volume->rescluster,
402 // rootblock->deldir, g);
404 /* reconfigure modules */
405 InitModules (volume
, FALSE
, g
);
407 /* restore references */
408 for (le
=HeadOf (&volume
->fileentries
); le
->next
; le
=le
->next
)
410 if (!IsVolumeEntry(le
))
412 if (!FetchObject(le
->diranodenr
, le
->anodenr
, &le
->info
, g
))
413 ErrorMsg(AFS_ERROR_UNSLEEP
, NULL
, g
); /* -> kill, invalidate lock <- */
418 fileentry_t
*fe
= (fileentry_t
*)le
;
420 /* restore anodechain and fe->currnode */
421 if (!(fe
->anodechain
= GetAnodeChain(fe
->le
.anodenr
, g
)))
422 ; /* kill, invalidate */
425 fe
->currnode
= &fe
->anodechain
->head
;
426 fe
->offset
= fe
->blockoffset
= fe
->anodeoffset
= 0;
427 if (SeekInObject(fe
, offset
, OFFSET_BEGINNING
, &error
, g
) == -1)
428 ErrorMsg(AFS_ERROR_UNSLEEP
, NULL
, g
); /* -> kill, invalidate */
434 // --> prevent 'normal' reference-restore on loading
437 /* unset sleepmode */
438 g
->sleepmode
= FALSE
;
441 g
->DoCommand
= NormalCommands
;
445 * Disk accessing packets are pending --> wake up!
446 * Handshaking sleeptask <-> AFS
448 static void Alarm (globaldata
*g
)
450 ULONG sleepmask
= 1<<g
->alarmsignal
;
452 /* signal task that we want to wake up */
453 Signal (g
->sleeptask
, sleepmask
);
457 WaitPort (g
->sleepport
);
465 * Reflect changed anode in locklist references
466 * returns number of references updated
469 static LONG
UpdateAnode (ULONG old
, ULONG
new, globaldata
*g
)
472 struct notifyobject
*no
;
474 struct volumedata
*volume
= g
->currentvolume
;
477 * Update fileentry list
480 for (le
=(listentry_t
*)HeadOf(&volume
->fileentries
); le
->next
; le
=le
->next
)
482 if (!IsVolumeEntry(le
))
484 if (le
->anodenr
== old
)
488 ; /* invalidate le */
492 if (le
->diranodenr
== old
)
495 le
->diranodenr
= new;
504 for (no
=HeadOf(&g
->currentvolume
->notifylist
); no
->next
; no
=no
->next
)
506 if (no
->anodenr
== old
)
517 * Message handler for messages on the sleepport
519 void HandleSleepMsg (globaldata
*g
)
523 while ((msg
= GetMsg (g
->sleepport
)))
527 g
->action
= (struct DosPacket
*)msg
->mn_Node
.ln_Name
;
528 (g
->DoCommand
)(g
->action
, g
);
532 g
->action
->dp_Res1
= DOSFALSE
;
533 g
->action
->dp_Res2
= ERROR_ACTION_NOT_KNOWN
;
536 ReturnPacket (g
->action
, g
->sleepport
, g
);