Added a test for MUIA_Listview_SelectChange.
[AROS.git] / rom / filesys / pfs3 / fs / volume.c
blob861ff13d721e7648c8f69c1b6ebafaafc6b82a8e
1 /* $Id$ */
2 /* $Log: volume.c $
3 * Revision 11.34 1999/09/11 17:05:14 Michiel
4 * bugfix version 18.4
6 * Revision 11.33 1999/05/14 11:31:34 Michiel
7 * Long filename support implemented; bugfixes
9 * Revision 11.32 1999/03/23 05:57:39 Michiel
10 * Autoupgrade bug involving MODE_SUPERDELDIR fixed
12 * Revision 11.31 1999/03/09 10:32:19 Michiel
13 * 00136: 1024 byte sector support
15 * Revision 11.30 1999/02/22 16:25:30 Michiel
16 * Changes for increasing deldir capacity
18 * Revision 11.29 1998/09/27 11:26:37 Michiel
19 * Dynamic rootblock allocation in GetCurrentRoot
20 * New ErrorMsg function that replaces macro
22 * Revision 11.28 1998/05/30 18:40:14 Michiel
23 * Title of error requesters was wrong
25 * Revision 11.27 1998/05/27 21:00:08 Michiel
26 * MODE_DATESTAMP is automatically turned on
28 * Revision 11.26 1998/05/22 22:59:58 Michiel
29 * Datestamps added
31 * Revision 11.25 1997/03/03 22:04:04 Michiel
32 * Release 16.21
34 * Revision 11.24 1996/03/29 17:00:11 Michiel
35 * bugfix: rootblock was freed with FreeVec instead of with FreeBufmem
37 * Revision 11.23 1996/01/30 12:50:39 Michiel
38 * Diskinsertsequence didn't used old instead of just read rootblock
39 * --- working tree overlap ---
41 * Revision 11.22 1996/01/03 10:04:35 Michiel
42 * simple change
44 * Revision 11.21 1995/11/15 16:00:05 Michiel
45 * Rootblock extension detection, loading and automatic creation
47 * Revision 11.20 1995/11/07 15:07:18 Michiel
48 * Adapted to new datacache (16.2)
49 * FreeUnusedResources() checks if volume
51 * Revision 11.19 1995/09/01 11:18:05 Michiel
52 * CheckCurrentVolumeBack added
53 * NormalErrorMsg changed. Extra argument that specifies the
54 * number of targets added.
56 * Revision 11.18 1995/08/21 04:23:11 Michiel
57 * Create deldir if it isn't there
59 * Revision 11.17 1995/08/04 04:23:01 Michiel
60 * use of MODE_SIZEFIELD added
62 * Revision 11.16 1995/07/21 06:58:07 Michiel
63 * DELDIR adaptions: MakeVolumeData, FreeVolumeResources
65 * Revision 11.15 1995/07/11 17:29:31 Michiel
66 * ErrorMsg () calls use messages.c variables now.
68 * Revision 11.14 1995/07/11 09:23:36 Michiel
69 * DELDIR stuff
71 * Revision 11.13 1995/07/07 14:38:47 Michiel
72 * AFSLITE stuff
74 * Revision 11.12 1995/07/07 10:14:12 Michiel
75 * changed CheckVolume()
77 * Revision 11.11 1995/06/19 09:43:19 Michiel
78 * softprotect of on diskchange
80 * Revision 11.10 1995/06/16 09:59:37 Michiel
81 * using Allec & FreeBufMem
83 * Revision 11.9 1995/06/15 18:56:53 Michiel
84 * pooled mem
86 * Revision 11.8 1995/05/20 12:12:12 Michiel
87 * Updated messages to reflect Ami-FileLock
88 * CUTDOWN version
89 * protection update
91 * Revision 11.7 1995/03/30 18:55:39 Michiel
92 * Initialization of notifylist added to MakeVolumeData()
94 * Revision 11.6 1995/02/15 16:43:39 Michiel
95 * Release version
96 * Using new headers (struct.h & blocks.h)
98 * Revision 11.5 1995/01/29 07:34:57 Michiel
99 * Raw res read/write and LOCK update
101 * Revision 11.4 1995/01/24 09:54:14 Michiel
102 * Cache hashing added
104 * Revision 11.3 1995/01/18 04:29:34 Michiel
105 * Bugfixes. Now ready for beta release.
107 * Revision 11.2 1995/01/15 05:26:44 Michiel
108 * fixed FreeVolumeResources bug
109 * inhibited trackdisk specific parts
111 * Revision 11.1 1995/01/08 16:24:01 Michiel
112 * Compiled (new MODE_BIG version)
114 * Revision 10.4 1994/11/15 17:52:30 Michiel
115 * GURU book update
117 * Revision 10.3 1994/10/29 08:55:42 Michiel
118 * changed process references to msgport references
120 * Revision 10.2 1994/10/27 11:38:17 Michiel
121 * Killed old Update() routines, that now reside in new_Update()
122 * MakeBlockDirty() now unconditionally sets g->dirty
124 * Revision 10.1 1994/10/24 11:16:28 Michiel
125 * first RCS revision
126 * */
128 //#define DEBUG 1
129 //#define DEBUGMODE 1
130 #define __USE_SYSBASE
132 #include <exec/types.h>
133 #include <exec/memory.h>
134 #include <exec/devices.h>
135 #include <exec/io.h>
136 #include <exec/interrupts.h>
137 #include <devices/input.h>
138 #include <devices/timer.h>
139 #include <dos/filehandler.h>
140 #include <intuition/intuition.h>
141 #include <proto/intuition.h>
142 #include <clib/alib_protos.h>
144 #include <string.h>
145 #include <stdlib.h>
146 #include <stdio.h>
147 #include <math.h>
148 #include <ctype.h>
150 #include "debug.h"
152 // own includes
153 #include "blocks.h"
154 #include "struct.h"
155 #include "directory_protos.h"
156 #include "volume_protos.h"
157 #include "disk_protos.h"
158 #include "allocation_protos.h"
159 #include "anodes_protos.h"
160 #include "update_protos.h"
161 #include "lru_protos.h"
162 #include "ass_protos.h"
163 #include "init_protos.h"
164 #include "format_protos.h"
166 static VOID CreateInputEvent(BOOL inserted, globaldata *g);
168 /**********************************************************************/
169 /* DEBUG */
170 /**********************************************************************/
172 #ifdef DEBUG
173 extern BOOL debug;
174 static UBYTE debugbuf[120];
175 #define DebugOn debug++
176 #define DebugOff debug=(debug?debug-1:0)
177 #define DebugMsg(msg) if(debug) {NormalErrorMsg(msg, NULL); debug=0;}
178 #define DebugMsgNum(msg, num) sprintf(debugbuf, "%s 0x%08lx.", msg, num); \
179 if(debug) {NormalErrorMsg(debugbuf, NULL); debug=0;}
180 #define DebugMsgName(msg, name) sprintf(debugbuf, "%s >%s<.", msg, name); \
181 if(debug) {NormalErrorMsg(debugbuf, NULL); debug=0;}
182 #else
183 #define DebugOn
184 #define DebugOff
185 #define DebugMsg(m)
186 #define DebugMsgNum(msg,num)
187 #define DebugMsgName(msg, name)
188 #endif
191 /**********************************************************************/
192 /* NEWVOLUME */
193 /* NEWVOLUME */
194 /* NEWVOLUME */
195 /**********************************************************************/
197 /* NewVolume
199 ** I Update diskchangenumber
200 ** :nochange->exit (tenzij FORCE = TRUE)
202 ** II New state = volume present?
203 ** :get id of new disk (read rootblock)
204 ** New disk = current disk?
205 ** :exit
207 ** III Old state = volume present?
208 ** :diskremoved-sequence
210 ** IV New state = volume present ?
211 ** :diskinserted-sequence
212 **-----
213 ** II-III-IV ordering is essential because diskremove-sequence has to be done before
214 ** diskinsert-sequence and diskremove-sequence can only be executed if newvolume <>
215 ** currentvolume
216 **-----
217 ** DiskRemove-sequence
219 ** I Clear globaldata->currentvolume (prevent infinite recursive loop)
221 ** II Changed blocks in cache ?
222 ** :request old volume (causes recursive call)
223 ** :update volume
224 ** :exit
226 ** III Locks/files open on volume?
227 ** yes: link locks in doslist
228 ** clear volume task field
229 ** no: remove volume from doslist
230 ** free all volume resources
231 **-----
232 ** DiskInsert-sequence
234 ** I Search new disk in volumelist
235 ** found: take over volume and locklist
236 ** ~found: make new volumestructure
237 ** link volume in doslist
239 ** II Update globaldata->currentvolume
240 **----
241 ** use FORCE to force a new volume even if the changecount is equal
243 static BOOL SameDisk(struct rootblock *, struct rootblock *);
244 static BOOL SameDiskDL(struct rootblock *, struct DeviceList *);
245 static void TakeOverLocks(struct FileLock *, globaldata *);
247 void NewVolume (BOOL FORCE, globaldata *g)
249 BOOL oldstate, newstate, changed;
250 struct rootblock *rootblock;
252 /* check if something changed */
253 changed = UpdateChangeCount (g);
254 if (!FORCE && !changed)
255 return;
257 ENTER("NewVolume");
258 FlushDataCache (g);
260 /* newstate <=> there is a PFS disk present */
261 oldstate = g->currentvolume ? TRUE : FALSE;
262 newstate = GetCurrentRoot (&rootblock, g);
264 /* undo error enforced softprotect */
265 if ((g->softprotect == 1) && g->protectkey == ~0)
266 g->softprotect = g->protectkey = 0;
268 if (oldstate && !newstate)
269 DiskRemoveSequence (g);
271 if (newstate)
273 if (oldstate && SameDisk (rootblock, g->currentvolume->rootblk))
275 FreeBufmem (rootblock, g); /* @XLVII */
277 else
279 if (oldstate)
280 DiskRemoveSequence (g);
281 DiskInsertSequence (rootblock, g);
284 else
286 g->currentvolume = NULL; /* @XL */
289 MotorOff (g);
290 EXIT("NewVolume");
294 /* pre:
295 ** globaldata->currentvolume not necessarily present
296 ** post:
297 ** the old currentvolume is updated en als 'removed' currentvolume == 0
298 ** return waarde = currentdisk back in drive?
299 ** used by NewVolume and ACTION_INHIBIT
301 void DiskRemoveSequence(globaldata *g)
303 struct volumedata *oldvolume = g->currentvolume;
305 ENTER("DiskRemoveSequence");
307 /* -I- update disk
308 ** will ask for old volume if there are unsaved changes
309 ** causes recursive NewVolume call. That's why 'currentvolume'
310 ** has to be cleared first; UpdateDisk won't be called for the
311 ** same disk again
313 if(oldvolume && g->dirty)
315 RequestCurrentVolumeBack(g);
316 UpdateDisk(g);
317 return;
320 /* disk removed */
321 g->currentvolume = NULL;
322 FlushDataCache (g);
324 /* -II- link locks in doslist
325 ** lockentries: link to doslist...
326 ** fileentries: link them too...
328 Forbid(); /* LockDosList(LDF_VOLUMES|LDF_READ); */
329 if(!IsMinListEmpty(&oldvolume->fileentries))
331 DB(Trace(1, "DiskRemoveSequence", "there are locks\n"));
332 oldvolume->devlist->dl_LockList = MKBADDR(&(((listentry_t *)(HeadOf(&oldvolume->fileentries)))->lock));
333 oldvolume->devlist->dl_Task = NULL;
334 FreeUnusedResources(oldvolume, g);
336 else
338 DB(Trace(1, "DiskRemoveSequence", "removing doslist\n"));
339 RemDosEntry((struct DosList*)oldvolume->devlist);
340 FreeDosEntry((struct DosList*)oldvolume->devlist);
341 MinRemove(oldvolume);
342 FreeVolumeResources(oldvolume, g);
344 Permit(); /* UnLockDosList(LDF_VOLUMES|LDF_READ); */
346 #ifdef TRACKDISK
347 if(g->trackdisk)
349 g->request->iotd_Req.io_Command = CMD_CLEAR;
350 DoIO(g->request);
352 #endif
354 CreateInputEvent(FALSE, g);
356 #if ACCESS_DETECT
357 g->tdmode = ACCESS_UNDETECTED;
358 #endif
360 EXIT("DiskRemoveSequence");
361 return;
364 void DiskInsertSequence(struct rootblock *rootblock, globaldata *g)
366 struct DosList *doslist;
367 struct DosInfo *di;
368 struct DeviceList *devlist;
369 BOOL found = FALSE, added = FALSE;
370 UBYTE diskname[DNSIZE]; // or should it be a DSTR??
371 SIPTR locklist;
373 ENTER("DiskInsertSequence");
375 /* -I- Search new disk in volumelist */
377 BCPLtoCString(diskname, rootblock->diskname);
378 // doslist = LockDosList(LDF_VOLUMES|LDF_READ);
379 Forbid();
380 di = BADDR(((struct RootNode *)DOSBase->dl_Root)->rn_Info);
381 doslist = BADDR(di->di_DevInfo);
383 for (doslist = BADDR(di->di_DevInfo);doslist;doslist = BADDR(doslist->dol_Next))
385 if (doslist->dol_Type == DLT_VOLUME && SameDiskDL(rootblock, (struct DeviceList *)doslist))
387 found = TRUE;
388 break;
392 // while(!found)
393 // {
394 // doslist = NextDosEntry(doslist, LDF_VOLUMES);
396 // if(doslist && (doslist = FindDosEntry(doslist, diskname, LDF_VOLUMES)))
397 // found = SameDiskDL(rootblock, (struct DeviceList *)doslist);
398 // else
399 // break;
400 // }
402 if (found)
404 DB(Trace(1, "DiskInsertSequence", "found\n"));
406 devlist = (struct DeviceList *)doslist;
407 locklist = (SIPTR)BADDR(devlist->dl_LockList);
409 /* take over volume
410 ** use LOCKTOFILEENTRY(lock)->volume to get volumepointer
412 if(locklist)
414 fileentry_t *fe;
416 /* get volumepointer @XLXV */
417 fe = LOCKTOFILEENTRY(locklist);
418 if(fe->le.type.flags.type == ETF_VOLUME)
419 g->currentvolume = fe->le.info.volume.volume;
420 else
421 g->currentvolume = fe->le.volume;
423 /* update rootblock */
424 if (g->rootblock) FreeBufmem (g->rootblock, g);
425 g->rootblock =
426 g->currentvolume->rootblk = rootblock;
428 /* take over filelocks
429 ** lockentries: takeover, change taskfield
430 ** fileentries: don't change taskfield
432 TakeOverLocks((struct FileLock *)locklist, g);
433 devlist = (struct DeviceList *)doslist;
434 devlist->dl_LockList = BNULL;
435 devlist->dl_Task = g->msgport;
438 else
440 RemDosEntry(doslist); // @@ freeing rootblk etc?
441 FreeDosEntry(doslist);
442 found = FALSE; // an empty doslistentry is useless to us
445 // UnLockDosList(LDF_VOLUMES|LDF_READ);
446 Permit();
448 if(!found)
450 DB(Trace(1, "DiskInsertSequence", "not found %s\n", diskname));
452 /* make new doslist entry (MOET eerst (zie blz67 schrift) */
453 devlist = (struct DeviceList *)MakeDosEntry(diskname, DLT_VOLUME);
454 if(devlist)
456 /* devlist invullen. Diskname NIET @XLIX */
457 devlist->dl_Task = g->msgport;
458 devlist->dl_VolumeDate.ds_Days = rootblock->creationday;
459 devlist->dl_VolumeDate.ds_Minute = rootblock->creationminute;
460 devlist->dl_VolumeDate.ds_Tick = rootblock->creationtick;
461 devlist->dl_LockList = BNULL; // no locks open yet
462 devlist->dl_DiskType = rootblock->disktype;
463 added = AddDosEntry((struct DosList *)devlist);
466 /* make new volumestructure for inserted volume */
467 g->currentvolume = MakeVolumeData(rootblock, g);
468 MinAddHead(&g->volumes, g->currentvolume);
469 g->currentvolume->devlist = (struct DeviceList *)devlist;
471 /* check if things worked out */
472 if(!devlist || !added) // duplicate disks or out of memory
474 ErrorMsg (AFS_ERROR_DOSLIST_ADD, NULL, g);
475 if(devlist)
476 FreeDosEntry((struct DosList *)devlist);
477 FreeVolumeResources(g->currentvolume, g);
478 g->currentvolume = NULL;
481 CreateInputEvent(TRUE, g);
484 /* Reconfigure modules to new volume */
485 InitModules (g->currentvolume, FALSE, g);
487 /* create rootblockextension if its not there yet */
488 if (!g->currentvolume->rblkextension &&
489 g->diskstate != ID_WRITE_PROTECTED)
491 MakeRBlkExtension (g);
494 #if DELDIR
495 /* upgrade deldir */
496 if (rootblock->deldir)
498 struct cdeldirblock *ddblk;
499 int i, nr;
501 /* kill current deldir */
502 ddblk = (struct cdeldirblock *)AllocLRU(g);
503 if (ddblk)
505 if (RawRead ((UBYTE*)&ddblk->blk, RESCLUSTER, rootblock->deldir, g) == 0)
507 if (ddblk->blk.id == DELDIRID)
509 for (i=0; i<31; i++)
510 nr = ddblk->blk.entries[i].anodenr;
511 if (nr)
512 FreeAnodesInChain(nr, g);
515 FreeLRU ((struct cachedblock *)ddblk);
518 /* create new deldir */
519 SetDeldir(1, g);
520 ResToBeFreed(rootblock->deldir, g);
521 rootblock->deldir = 0;
522 rootblock->options |= MODE_SUPERDELDIR;
524 #endif
526 /* update datestamp and enable */
527 rootblock->options |= MODE_DATESTAMP;
528 rootblock->datestamp++;
529 g->dirty = TRUE;
531 EXIT("DiskInsertSequence");
534 /* check if rootblocks are of the same disk */
535 static BOOL SameDisk(struct rootblock *disk1, struct rootblock *disk2)
537 BOOL result;
539 result = disk1->creationday == disk2->creationday &&
540 disk1->creationminute == disk2->creationminute &&
541 disk1->creationtick == disk2->creationtick &&
542 ddstricmp(disk1->diskname, disk2->diskname);
544 return(result);
547 /* checks is devicelist belongs to rootblock */
548 static BOOL SameDiskDL(struct rootblock *disk1, struct DeviceList *disk2)
550 BOOL result;
552 result = ddstricmp(disk1->diskname, BADDR(disk2->dl_Name)) &&
553 disk1->creationday == disk2->dl_VolumeDate.ds_Days &&
554 disk1->creationminute == disk2->dl_VolumeDate.ds_Minute &&
555 disk1->creationtick == disk2->dl_VolumeDate.ds_Tick;
557 return(result);
560 /* make and fill in volume structure
561 * uses g->geom!
562 * returns 0 is fails
564 struct volumedata *MakeVolumeData (struct rootblock *rootblock, globaldata *g)
566 struct volumedata *volume;
567 struct MinList *list;
569 ENTER("MakeVolumeData");
571 volume = AllocMemPR (sizeof(struct volumedata), g);
573 volume->rootblk = rootblock;
574 volume->rootblockchangeflag = FALSE;
576 /* lijsten initieren */
577 for (list = &volume->fileentries; list <= &volume->notifylist; list++)
578 NewList((struct List *)list);
580 /* andere gegevens invullen */
581 volume->numsofterrors = 0;
582 volume->diskstate = ID_VALIDATED;
584 /* these could be put in rootblock @@ see also HD version */
585 volume->numblocks = g->geom->dg_TotalSectors;
586 volume->bytesperblock = g->geom->dg_SectorSize;
587 volume->rescluster = rootblock->reserved_blksize / volume->bytesperblock;
589 /* load rootblock extension (if it is present) */
590 if (rootblock->extension && (rootblock->options & MODE_EXTENSION))
592 struct crootblockextension *rext;
594 rext = AllocBufmemR (sizeof(struct cachedblock) + rootblock->reserved_blksize, g);
595 memset (rext, 0, sizeof(struct cachedblock) + rootblock->reserved_blksize);
596 if (RawRead ((UBYTE *)&rext->blk, volume->rescluster, rootblock->extension, g) != 0)
598 ErrorMsg (AFS_ERROR_READ_EXTENSION, NULL, g);
599 FreeBufmem (rext, g);
600 rootblock->options ^= MODE_EXTENSION;
602 else
604 if (rext->blk.id == EXTENSIONID)
606 volume->rblkextension = rext;
607 rext->volume = volume;
608 rext->blocknr = rootblock->extension;
610 else
612 ErrorMsg (AFS_ERROR_EXTENSION_INVALID, NULL, g);
613 FreeBufmem (rext, g);
614 rootblock->options ^= MODE_EXTENSION;
618 else
620 volume->rblkextension = NULL;
623 EXIT("MakeVolumeData");
624 return volume;
627 /* fill in my process at the task fields of the locks */
628 static void TakeOverLocks (struct FileLock *locklist, globaldata *g)
630 while (locklist)
632 locklist->fl_Task = g->msgport;
633 locklist = (struct FileLock *)BADDR(locklist->fl_Link);
637 /* free all resources (memory) taken by volume accept doslist
638 ** it is assumed all this data can be discarded (not checked here!)
639 ** it is also assumed this volume is no part of any volumelist
641 void FreeVolumeResources(struct volumedata *volume, globaldata *g)
643 ENTER("Free volume resources");
645 if (volume)
647 FreeUnusedResources (volume, g);
648 #if VERSION23
649 if (volume->rblkextension)
650 FreeBufmem (volume->rblkextension, g);
651 #endif
652 #if DELDIR
653 // if (g->deldirenabled)
654 // FreeBufmem (volume->deldir, g);
655 #endif
656 FreeBufmem (volume->rootblk, g);
657 FreeMemP (volume, g);
660 EXIT("FreeVolumeResources");
663 void FreeUnusedResources(struct volumedata *volume, globaldata *g)
665 struct MinList *list;
666 struct MinNode *node, *next;
668 ENTER("FreeUnusedResources");
670 /* check if volume passed */
671 if (!volume)
672 return;
674 /* start with anblks!, fileentries are to be kept! */
675 for (list = volume->anblks; list<=&volume->bmindexblks; list++)
677 node = (struct MinNode *)HeadOf(list);
678 while ((next = node->mln_Succ))
680 FlushBlock((struct cachedblock *)node, g);
681 FreeLRU((struct cachedblock *)node);
682 node = next;
688 /* CreateInputEvent
690 ** generate a `disk inserted/removed' event, in order to get Workbench to
691 ** rescan the DosList and update the list of volume icons.
693 ** function supplied by Nicola Salmoria
695 static VOID CreateInputEvent(BOOL inserted, globaldata *g)
697 struct MsgPort *port;
699 port = CreateMsgPort();
700 if (port)
702 struct IOStdReq *io;
704 #ifdef __SASC
705 io = CreateStdIO(port);
706 #else
707 io = CreateIORequest(port, sizeof(*io));
708 #endif
709 if (io)
711 if (!OpenDevice("input.device",0,(struct IORequest *)io,0))
713 struct InputEvent ie;
715 memset(&ie,0,sizeof(struct InputEvent));
716 ie.ie_Class = inserted ? IECLASS_DISKINSERTED : IECLASS_DISKREMOVED;
717 io->io_Command = IND_WRITEEVENT;
718 io->io_Data = &ie;
719 io->io_Length = sizeof(struct InputEvent);
720 DoIO((struct IORequest *)io);
722 CloseDevice((struct IORequest *)io);
725 #ifdef __SASC
726 DeleteStdIO(io);
727 #else
728 DeleteIORequest(io);
729 #endif
732 DeleteMsgPort(port);
737 /**********************************************************************/
738 /* OTHER VOLUMEROUTINES */
739 /* OTHER VOLUMEROUTINES */
740 /* OTHER VOLUMEROUTINES */
741 /**********************************************************************/
743 /* Update the changecount
744 ** returns TRUE if changecount changed
746 BOOL UpdateChangeCount(globaldata *g)
748 struct IOExtTD *request = g->request;
749 ULONG changecount;
750 BOOL result;
752 if(g->removable)
754 ENTER("UpdateChangeCount");
755 request->iotd_Req.io_Command = TD_CHANGENUM;
756 if(DoIO((struct IORequest *)request) == 0)
757 changecount = request->iotd_Req.io_Actual;
758 else
759 changecount = ~0;
761 result = (changecount != g->changecount);
762 g->changecount = changecount;
763 return(result);
765 else
767 return 0; /* no change */
771 /* checks if disk is changed. If so calls NewVolume()
772 ** NB: new volume might be NOVOLUME or NOTAFDSDISK
774 void UpdateCurrentDisk(globaldata *g)
776 NewVolume(0, g);
779 /* CheckVolume checks if a volume (ve lock) is (still) present.
780 ** If volume==NULL (no disk present) then FALSE is returned (@XLII).
781 ** result: requested volume present/not present TRUE/FALSE
783 BOOL CheckVolume(struct volumedata *volume, BOOL write, SIPTR *error, globaldata *g)
785 if(!volume || !g->currentvolume)
787 switch(g->disktype)
790 case ID_UNREADABLE_DISK:
791 case ID_NOT_REALLY_DOS:
792 *error = ERROR_NOT_A_DOS_DISK;
793 return(DOSFALSE);
795 case ID_NO_DISK_PRESENT:
796 if(!volume && !g->currentvolume)
798 *error = ERROR_NO_DISK;
799 return(DOSFALSE);
802 default:
803 *error = ERROR_DEVICE_NOT_MOUNTED;
804 return(DOSFALSE);
807 else if(g->currentvolume == volume)
809 switch(g->diskstate)
811 case ID_WRITE_PROTECTED:
812 if(write)
814 *error = ERROR_DISK_WRITE_PROTECTED;
815 return(DOSFALSE);
818 case ID_VALIDATING:
819 if(write)
821 *error = ERROR_DISK_NOT_VALIDATED;
822 return(DOSFALSE);
825 case ID_VALIDATED:
826 if(write && g->softprotect)
828 *error = ERROR_DISK_WRITE_PROTECTED;
829 return(DOSFALSE);
832 default:
833 return(DOSTRUE);
836 else
838 *error = ERROR_DEVICE_NOT_MOUNTED;
839 return(DOSFALSE);
844 /**********************************************************************/
845 /* REQUESTERS */
846 /* REQUESTERS */
847 /* REQUESTERS */
848 /**********************************************************************/
851 * ErrorMsg wrapper function
853 LONG ErrorMsg(CONST_STRPTR msg, APTR arg, globaldata *g)
855 LONG rv;
856 char charbuffer[256], *b;
858 b = stpcpy(charbuffer, "Device ");
859 strncpy(b, &g->mountname[1], g->mountname[0]);
860 b += g->mountname[0];
861 b = stpcpy(b, ":\n");
862 b = stpcpy(b, msg);
864 rv = (g->ErrorMsg)(charbuffer,arg,1,g);
865 if (!g->softprotect) {
866 g->softprotect = 1;
867 g->protectkey = ~0;
869 if (g->currentvolume)
870 g->currentvolume->numsofterrors++;
871 return rv;
875 /* All possible ErrorMsg routines
877 ** Displays easyrequest with error message
878 ** Intuition library has to be opened
880 static const CONST_STRPTR gadgets[] =
882 "OK", "RETRY|CANCEL"
885 LONG _NormalErrorMsg(CONST_STRPTR melding, APTR arg, ULONG notargets, globaldata *g)
887 struct EasyStruct req;
890 * Make sure we don't hold the performance semaphore while displaying
891 * a requester. Note that unlock_device_unit is safe to call multiple
892 * times, and even when not holding a lock. Unlock also is safe to call
893 * before init has been called.
895 unlock_device_unit(g);
897 req.es_StructSize = sizeof(req);
898 req.es_Flags = 0;
899 req.es_Title = "PFS-III Error Requester";
900 req.es_TextFormat = (STRPTR)melding;
901 req.es_GadgetFormat = (STRPTR)gadgets[notargets-1];
902 return EasyRequestArgs(NULL, &req, NULL, arg);
906 /* Don't show up a error requester. Used by GetCurrentRoot */
907 static LONG NoErrorMsg(CONST_STRPTR melding, APTR arg, ULONG dummy, globaldata *g)
909 return 0;
912 /***********************************************************************/
913 /* LOWLEVEL */
914 /* LOWLEVEL */
915 /* LOWLEVEL */
916 /***********************************************************************/
918 /* Load the rootblock of the volume that is currently in the drive.
919 * Returns FLASE if no disk or no PFS disk and TRU if it is a PFS disk.
920 * Sets disktype in globaldata->disktype
921 * Should NOT change globaldata->currentvolume
923 * Allocates space in 'rootblock' which is freed if an error occurs.
926 #ifdef TRACKDISK
927 static void UpdateDosEnvec(globaldata *g);
928 #endif
930 BOOL GetCurrentRoot(struct rootblock **rootblock, globaldata *g)
932 BOOL changestate;
933 ULONG error;
934 struct IOExtTD *request = g->request;
935 int rblsize;
937 ENTER("GetCurrentRoot");
939 if (g->removable)
941 /* init */
942 UpdateChangeCount(g);
944 /* added %9.5.1
945 ** ESSENTIAL for diskspare.device
946 ** if not present problems with interleaving FFS disks
948 #ifdef TRACKDISK
949 if (g->trackdisk)
951 g->request->iotd_Req.io_Command = CMD_CLEAR;
952 DoIO(g->request);
954 #endif
956 /* Get volumepresentstate */
957 request->iotd_Req.io_Command = TD_CHANGESTATE;
958 if (DoIO((struct IORequest *)request) == 0)
960 /* changestate <=> there is a disk present */
961 changestate = !request->iotd_Req.io_Actual;
962 if (!changestate)
964 if ((g->disktype == ID_NOT_REALLY_DOS) || (g->disktype == ID_UNREADABLE_DISK))
965 CreateInputEvent(FALSE, g);
966 g->disktype = ID_NO_DISK_PRESENT;
967 return DOSFALSE;
972 /* get drive geometry table (V4.3) */
973 GetDriveGeometry(g);
975 /* Get diskprotection @XLI */
976 request->iotd_Req.io_Command = TD_PROTSTATUS;
977 if (DoIO((struct IORequest *)request) == 0)
979 if (request->iotd_Req.io_Actual)
980 g->diskstate = ID_WRITE_PROTECTED;
981 else
982 g->diskstate = ID_VALIDATED;
984 else
986 g->diskstate = ID_VALIDATED;
987 DB(Trace(1, "GetCurrentRoot", "TD_PROTSTATUS failed\n"));
990 /* check if disk is PFS disk */
991 *rootblock = AllocBufmemR (BLOCKSIZE, g);
992 g->ErrorMsg = NoErrorMsg; // prevent readerrormsg
994 #if ACCESS_DETECT
995 /* detect best access mode, td32, td64, nsd or directscsi */
996 if (g->tdmode == ACCESS_UNDETECTED) {
997 if (!detectaccessmode((UBYTE*)*rootblock, g))
998 goto nrd_error;
1000 #endif
1002 error = RawRead((UBYTE *)*rootblock, 1, BOOTBLOCK1, g);
1003 g->ErrorMsg = _NormalErrorMsg;
1005 if (!error)
1007 if ((*rootblock)->disktype == ID_PFS_DISK || (*rootblock)->disktype == ID_PFS2_DISK)
1009 g->disktype = ID_PFS_DISK;
1010 error = RawRead((UBYTE *)*rootblock, 1, ROOTBLOCK, g);
1011 if (!error)
1013 /* check size and read all rootblock blocks */
1014 // 17.10: with 1024 byte blocks rblsize can be 1!
1015 rblsize = (*rootblock)->rblkcluster;
1016 if (rblsize < 1 || rblsize > 512)
1017 goto nrd_error;
1019 if (!InitLRU(g, (*rootblock)->reserved_blksize))
1020 goto nrd_error;
1022 FreeBufmem(*rootblock, g);
1023 *rootblock = AllocBufmemR (rblsize << BLOCKSHIFT, g);
1024 error = RawRead((UBYTE *)*rootblock, rblsize, ROOTBLOCK, g);
1027 /* size check */
1028 if (((*rootblock)->options & MODE_SIZEFIELD) &&
1029 (g->geom->dg_TotalSectors != (*rootblock)->disksize))
1031 goto nrd_error;
1034 return DOSTRUE;
1037 nrd_error:
1038 g->disktype = ID_NOT_REALLY_DOS;
1039 CreateInputEvent(TRUE, g);
1040 FreeBufmem (*rootblock, g);
1041 *rootblock = NULL;
1042 return DOSFALSE;
1044 else if (error == TDERR_DiskChanged)
1046 if ((g->disktype == ID_NOT_REALLY_DOS) || (g->disktype == ID_UNREADABLE_DISK))
1047 CreateInputEvent(FALSE, g);
1048 g->disktype = ID_NO_DISK_PRESENT;
1049 FreeBufmem (*rootblock, g);
1050 *rootblock = NULL;
1051 return DOSFALSE;
1053 else
1055 if (g->diskstate != ID_WRITE_PROTECTED)
1056 g->diskstate = ID_VALIDATING;
1058 g->disktype = ID_UNREADABLE_DISK;
1059 CreateInputEvent(TRUE, g);
1060 FreeBufmem (*rootblock, g);
1061 *rootblock = NULL;
1062 return DOSFALSE;
1067 /* Get drivegeometry from diskdevice.
1068 ** If TD_GETGEOMETRY fails the DOSENVEC values are taken
1069 ** Dosenvec is taken into consideration
1071 void GetDriveGeometry(globaldata *g)
1073 IPTR *env = (IPTR *)g->dosenvec;
1074 struct DriveGeometry *geom = g->geom;
1075 UBYTE error = 1;
1077 #ifdef TRACKDISK
1078 struct IOExtTD *request = g->request;
1080 if(g->trackdisk)
1082 request->iotd_Req.io_Data = geom;
1083 request->iotd_Req.io_Command = TD_GETGEOMETRY;
1084 request->iotd_Req.io_Length = sizeof(struct DriveGeometry);
1085 if(!(error = DoIO((struct IORequest *)request)))
1086 UpdateDosEnvec(g);
1088 #endif
1090 if(error || !g->trackdisk)
1092 geom->dg_SectorSize = env[DE_SIZEBLOCK] << 2;
1093 geom->dg_Cylinders = env[DE_UPPERCYL] - env[DE_LOWCYL] + 1;
1094 geom->dg_CylSectors = env[DE_NUMHEADS] * env[DE_BLKSPERTRACK];
1095 geom->dg_TotalSectors = g->geom->dg_Cylinders *
1096 g->geom->dg_CylSectors;
1097 geom->dg_Heads = env[DE_NUMHEADS];
1098 geom->dg_TrackSectors = env[DE_BLKSPERTRACK];
1099 geom->dg_BufMemType = env[DE_MEMBUFTYPE];
1100 geom->dg_DeviceType = DG_UNKNOWN;
1101 geom->dg_Flags = 0;
1104 g->firstblock = g->dosenvec->de_LowCyl * geom->dg_CylSectors;
1105 g->lastblock = (g->dosenvec->de_HighCyl + 1) * geom->dg_CylSectors - 1;
1106 #if LIMIT_MAXTRANSFER
1107 /* A600/A1200/A4000 ROM scsi.device ATA spec max transfer bug workaround */
1108 g->maxtransfer = min(g->dosenvec->de_MaxTransfer, LIMIT_MAXTRANSFER);
1109 #else
1110 g->maxtransfer = g->dosenvec->de_MaxTransfer;
1111 #endif
1112 DB(Trace(1,"GetDriveGeometry","firstblk %ld lastblk %ld\n",g->firstblock,g->lastblock));
1116 #ifdef TRACKDISK
1117 /* UpdateDosEnvec
1118 ** Adapt dosenvec to the current drivegeometry
1119 ** DO NOT call this function if you use partitions (ONLY called by GetDriveGeometry)
1121 static void UpdateDosEnvec(globaldata *g)
1123 ULONG *env;
1124 struct DriveGeometry *geom;
1125 ULONG size;
1127 // LockDosList(LDF_DEVICES|LDF_READ);
1128 Forbid();
1130 geom = g->geom;
1131 env = (ULONG *)g->dosenvec;
1132 size = env[DE_TABLESIZE];
1134 if(size > DE_SIZEBLOCK)
1135 env[DE_SIZEBLOCK] = geom->dg_SectorSize >> 2;
1137 if(size > DE_NUMHEADS)
1138 env[DE_NUMHEADS] = geom->dg_Heads;
1140 if(size > DE_BLKSPERTRACK)
1141 env[DE_BLKSPERTRACK] = geom->dg_TrackSectors;
1143 if(size > DE_LOWCYL)
1144 env[DE_LOWCYL] = 0;
1146 if(size > DE_UPPERCYL)
1147 env[DE_UPPERCYL] = geom->dg_Cylinders - 1;
1149 // UnLockDosList(LDF_DEVICES|LDF_READ);
1150 Permit();
1152 #endif
1155 /* Get the currentvolume back in the drive
1157 void RequestCurrentVolumeBack(globaldata *g)
1159 UBYTE volumename[DNSIZE];
1160 BOOL ready = FALSE;
1161 struct rootblock *rootblock;
1162 struct volumedata *volume = g->currentvolume;
1164 ENTER("GetCurrentVolumeBack");
1166 BCPLtoCString(volumename, volume->rootblk->diskname);
1168 while(!ready)
1170 ready = GetCurrentRoot(&rootblock, g) && SameDisk(volume->rootblk, rootblock);
1171 if(!ready)
1172 ErrorReport(ABORT_BUSY, REPORT_VOLUME, (IPTR)MKBADDR(volume->devlist), NULL);
1175 if (rootblock)
1176 FreeBufmem (rootblock, g);
1179 BOOL CheckCurrentVolumeBack (globaldata *g)
1181 BOOL ready = FALSE;
1182 struct rootblock *rootblock;
1183 struct volumedata *volume = g->currentvolume;
1185 ready = GetCurrentRoot(&rootblock, g) && SameDisk(volume->rootblk, rootblock);
1186 if (rootblock)
1187 FreeBufmem (rootblock, g);
1188 return ready;