revert between 56095 -> 55830 in arch
[AROS.git] / rom / filesys / SFS / SFScheck / SFScheck.c
blob9cb8a0ed2849caf7b00b78fe3d063fbf1d0a4b40
1 #include <clib/macros.h>
2 #include <devices/scsidisk.h>
3 #include <devices/trackdisk.h>
4 #include <dos/dos.h>
5 #include <dos/dosextens.h>
6 #include <dos/filehandler.h>
7 #include <exec/errors.h>
8 #include <exec/io.h>
9 #include <exec/memory.h>
10 #include <proto/dos.h>
11 #include <proto/exec.h>
12 #include <proto/intuition.h>
13 #include <string.h>
14 #include "stdio.h"
16 #include "../FS/globals.h"
17 #include "../FS/deviceio.h"
18 #include "../FS/deviceio_protos.h"
19 #include "../FS/cachedio_protos.h"
20 #include "../FS/asmsupport.h"
21 #include "../FS/adminspaces.h"
22 #include "../FS/bitmap.h"
23 #include "../FS/objects.h"
24 #include "../FS/transactions.h"
25 #include "../FS/fs.h"
26 #include "../FS/btreenodes.h"
29 #define BLCKFACCURACY (5) /* 2^5 = 32 */
32 const char version[]={"\0$VER: SFSCheck 1.3 (" ADATE ")r\n"};
35 LONG read2(ULONG block);
36 void dumpblock(ULONG block, void *data, ULONG bytes);
37 void sfscheck(void);
38 BOOL iszero(void *a,LONG size);
39 BOOL isblockvalid(void *b, ULONG block, ULONG id);
40 LONG findbnode(BLCK rootblock,ULONG key,struct BNode **returned_bnode);
41 UBYTE *mark(LONG offset, LONG blocks);
42 BOOL error(UBYTE *fmt, ... );
43 void freestring(UBYTE *str);
44 UBYTE *tostring(UBYTE *fmt, ... );
46 ULONG errors=0;
47 ULONG maxerrors=10;
48 UBYTE emptystring[]="";
50 UBYTE string[200];
52 struct DosEnvec *dosenvec;
54 /* blocks_ = the number of blocks of something (blocks can contain 1 or more sectors)
55 block_ = a block number of something (relative to start of partition)
56 sectors_ = the number of sectors of something (1 or more sectors form a logical block)
57 sector_ = a sector number (relative to the start of the disk)
58 bytes_ = the number of bytes of something
59 byte_ = a byte number of something
60 shifts_ = the number of bytes written as 2^x of something
61 mask_ = a mask for something */
63 ULONG blocks_reserved_start; /* number of blocks reserved at start (=reserved) */
64 ULONG blocks_reserved_end; /* number of blocks reserved at end (=prealloc) */
65 ULONG blocks_bitmap; /* number of BTMP blocks for this partition */
66 ULONG blocks_inbitmap; /* number of blocks a single bitmap block can contain info on */
67 ULONG blocks_admin; /* the size of all AdminSpaces */
69 ULONG block_root; /* the block offset of the root block */
70 ULONG block_bitmapbase; /* the block offset of the first bitmap block */
71 ULONG block_extentbnoderoot; /* the block offset of the root of the extent bnode tree */
72 ULONG block_adminspace; /* the block offset of the first adminspacecontainer block */
73 ULONG block_rovingblockptr; /* the roving block pointer! */
74 ULONG block_objectnodesbase;
76 ULONG node_containers; /* number of containers per ExtentIndexContainer */
78 ULONG mask_block32; /* masks the least significant bits of a BLCKf pointer */
80 UWORD shifts_block32; /* shift count needed to convert a blockoffset<->32byteoffset (only used by nodes.c!) */
82 void *pool;
84 UBYTE *buffer;
85 ULONG *bitmap;
87 ULONG returncode=0;
89 LONG main() {
90 struct RDArgs *readarg;
91 UBYTE template[]="DEVICE=DRIVE/A,LOCK/S,LINES/N,READAHEADSIZE/N\n";
93 struct {char *device;
94 ULONG lock;
95 ULONG *lines;
96 ULONG *readaheadsize;} arglist={NULL};
98 globals = AllocMem(sizeof(struct SFSBase), MEMF_PUBLIC | MEMF_CLEAR);
99 if(globals==NULL)
100 return RETURN_FAIL;
101 initGlobals();
103 if((DOSBase=(struct DosLibrary *)OpenLibrary("dos.library",39))!=0) {
104 if((IntuitionBase=(APTR)OpenLibrary("intuition.library",39))!=0) {
105 if((pool=CreatePool(0,16384,8192))!=0) {
106 if((readarg=ReadArgs(template,(IPTR *)&arglist,0))!=0) {
107 struct DosList *dl;
108 UBYTE *devname=arglist.device;
110 while(*devname!=0) {
111 if(*devname==':') {
112 *devname=0;
113 break;
115 devname++;
118 dl=LockDosList(LDF_DEVICES|LDF_READ);
119 if((dl=FindDosEntry(dl,arglist.device,LDF_DEVICES))!=0) {
120 struct FileSysStartupMsg *fssm;
121 LONG errorcode;
123 fssm=(struct FileSysStartupMsg *)BADDR(dl->dol_misc.dol_handler.dol_Startup);
124 dosenvec=(struct DosEnvec *)BADDR(fssm->fssm_Environ);
126 UnLockDosList(LDF_DEVICES|LDF_READ);
128 if(arglist.lock==0 || Inhibit(arglist.device, DOSTRUE)!=DOSFALSE) {
130 if((initcachedio(AROS_BSTR_ADDR(fssm->fssm_Device), fssm->fssm_Unit, fssm->fssm_Flags, dosenvec))==0) {
132 setiocache(arglist.lines!=0 ? *arglist.lines : 128, arglist.readaheadsize!=0 ? *arglist.readaheadsize : 8192, FALSE); /* 1 MB for read-ahead cache, no copyback mode. */
134 shifts_block32=globals->shifts_block-BLCKFACCURACY;
136 mask_block32=(1<<shifts_block32)-1;
138 blocks_reserved_start=MAX(dosenvec->de_Reserved,1);
139 blocks_reserved_end=MAX(dosenvec->de_PreAlloc,1);
141 blocks_inbitmap=(globals->bytes_block-sizeof(struct fsBitmap))<<3; /* must be a multiple of 32 !! */
142 blocks_bitmap=(globals->blocks_total+blocks_inbitmap-1)/blocks_inbitmap;
143 blocks_admin=32;
145 printf("Partition start offset : 0x%llx End offset : 0x%llx\n", (unsigned long long)globals->byte_low, (unsigned long long)globals->byte_high);
146 printf("Surfaces : %-5ld Blocks/Track : %ld\n", dosenvec->de_Surfaces, dosenvec->de_BlocksPerTrack);
147 printf("Bytes/Block : %-5ld Sectors/Block : %ld\n", (long)globals->bytes_block, dosenvec->de_SectorPerBlock);
148 printf("Total blocks : %ld\n", (long)globals->blocks_total);
149 printf("Device interface : ");
151 switch(deviceapiused()) {
152 case DAU_NSD:
153 printf("NSD (64-bit)\n");
154 break;
155 case DAU_TD64:
156 printf("TD64\n");
157 break;
158 case DAU_SCSIDIRECT:
159 printf("SCSI direct\n");
160 break;
161 default:
162 printf("(standard)\n");
163 break;
166 if((buffer=AllocVec(globals->bytes_block, globals->bufmemtype))!=0) {
167 if((bitmap=AllocVec(((globals->blocks_total+31)>>5)<<3,MEMF_CLEAR))!=0) {
168 UBYTE *str;
170 bitmap[globals->blocks_total>>5]=L2BE(0xFFFFFFFF>>(globals->blocks_total & 0x0000001F));
171 if((str=mark(0,blocks_reserved_start))!=0) {
172 printf("Error while marking reserved blocks at start:\n%s",str);
173 freestring(str);
175 if((str=mark(globals->blocks_total-blocks_reserved_end,blocks_reserved_end))!=0) {
176 printf("Error while marking reserved blocks at end:\n%s",str);
177 freestring(str);
180 sfscheck();
182 FreeVec(bitmap);
184 else {
185 printf("Not enough memory\n");
187 FreeVec(buffer);
189 else {
190 printf("Not enough memory\n");
193 cleanupcachedio();
196 if(arglist.lock!=0) {
197 Inhibit(arglist.device, DOSFALSE);
200 else {
201 errorcode = IoErr();
202 PrintFault(errorcode, "error while locking the drive");
205 else {
206 Printf("Unknown device %s\n", arglist.device);
207 UnLockDosList(LDF_DEVICES|LDF_READ);
210 FreeArgs(readarg);
212 DeletePool(pool);
214 CloseLibrary((struct Library *)IntuitionBase);
216 CloseLibrary((struct Library *)DOSBase);
218 return(returncode);
224 else if(SetSignal(0L,SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) {
225 PutStr("\n***Break\n");
226 break;
231 BOOL validblock(ULONG block) {
232 if(block<globals->blocks_total) {
233 return(TRUE);
235 return(FALSE);
240 LONG read2(ULONG block) {
241 // return(transfer(DIO_READ, buffer, block, 1));
242 return(read(block, buffer, 1));
247 BOOL checkchecksum(void *d) {
248 ULONG *data=(ULONG *)d;
250 if(CALCCHECKSUM(globals->bytes_block,data)==0) {
251 return(TRUE);
253 return(FALSE);
258 BOOL checkobjectcontainerblock(struct fsObjectContainer *b, ULONG block) {
259 if(isblockvalid(b,block,OBJECTCONTAINER_ID)!=FALSE) {
263 return(FALSE);
268 BOOL checkbitmapblock(struct fsBitmap *b, ULONG block, ULONG sequencenumber) {
269 if(isblockvalid(b,block,BITMAP_ID)!=FALSE) {
270 ULONG l=(sequencenumber-1)*(blocks_inbitmap>>5);
271 WORD n=blocks_inbitmap>>5;
272 ULONG *bm=b->bitmap;
274 if(sequencenumber==blocks_bitmap) {
275 n=((globals->blocks_total - ((blocks_bitmap-1) * blocks_inbitmap))+31)>>5;
278 while(--n>=0 && ~bitmap[l++]==*bm++) {
282 if(n<0) {
283 if(sequencenumber==blocks_bitmap) {
284 if((bmffo(b->bitmap, blocks_inbitmap>>5, globals->blocks_total - ((blocks_bitmap-1) * blocks_inbitmap) ))==blocks_inbitmap) {
285 return(TRUE);
287 else {
288 printf("Last bitmap block wasn't correctly filled out with 0's\n");
291 else {
292 return(TRUE);
295 else {
296 printf("%ld %08lx == %08lx\n",(long)n,(unsigned long)~bitmap[--l],(unsigned long)*--bm);
297 printf("Bitmap block %ld contents is incorrect!\n",(long)block);
298 return(TRUE);
302 return(FALSE);
307 BOOL checkbitmap(ULONG block) {
308 LONG n;
310 for(n=1; n<=blocks_bitmap; n++) {
311 read2(block);
312 if(checkbitmapblock((struct fsBitmap *)buffer, block, n)==FALSE) {
313 printf("...error in bitmap block at block %ld\n",(long)block);
314 return(FALSE);
316 block++;
319 return(TRUE);
324 BOOL checkrootblock(struct fsRootBlock *b, ULONG block) {
325 if(isblockvalid(b,block,L2BE(DOSTYPE_ID))!=FALSE) {
326 if(b->be_version==W2BE(STRUCTURE_VERSION)) {
327 if(b->pad1==0 && b->be_pad2==0 && iszero(b->be_reserved1,8) && iszero(b->be_reserved2,8) && iszero(b->be_reserved3,32) && iszero(b->be_reserved4,16) && iszero((UBYTE *)b+sizeof(struct fsRootBlock),globals->bytes_block-sizeof(struct fsRootBlock))) {
328 if(BE2L(b->be_totalblocks)==globals->blocks_total) {
329 if(BE2L(b->be_blocksize)==globals->bytes_block) {
330 return(TRUE);
332 else {
333 printf("RootBlock's blocksize field is %ld, while it should be %ld.\n",(long)BE2L(b->be_blocksize),(long)globals->bytes_block);
336 else {
337 printf("RootBlock's total number of blocks is %ld, while it should be %ld.\n",(long)BE2L(b->be_totalblocks),(long)globals->blocks_total);
340 else {
341 printf("Reserved areas in RootBlock weren't all set to zero.\n");
344 else {
345 printf("RootBlock's version is unsupported by this version of SFScheck\n");
349 return(FALSE);
354 BOOL isblockvalid(void *bh, ULONG block, ULONG id) {
355 struct fsBlockHeader *b=(struct fsBlockHeader *)bh;
357 if(checkchecksum((UBYTE *)b)!=FALSE) {
358 if(b->id==id) {
359 if(BE2L(b->be_ownblock)==block) {
360 return(TRUE);
362 else {
363 printf("Location of block is invalid.\n");
366 else {
367 printf("Incorrect block type at block %ld. Expected was 0x%08lx but it was 0x%08lx.\n",(long)block,(unsigned long)BE2L(id),(unsigned long)BE2L(b->id));
370 else {
371 printf("Checksum failure.\n");
374 return(FALSE);
379 BOOL iszero(void *a,LONG size) {
380 UBYTE *adr=(UBYTE *)a;
382 while(--size>=0 && *adr++==0) {
385 if(size>=0) {
386 return(FALSE);
388 return(TRUE);
393 struct fsObject *nextobject(struct fsObject *o) {
394 UBYTE *p;
396 /* skips the passed in fsObject and gives a pointer back to the place where
397 a next fsObject structure could be located */
399 p=(UBYTE *)&o->name[0];
401 /* skip the filename */
402 while(*p++!=0) {
405 /* skip the comment */
406 while(*p++!=0) {
409 /* ensure WORD boundary */
410 if((((IPTR)p) & 0x01)!=0) {
411 p++;
414 return((struct fsObject *)p);
419 WORD isobject(struct fsObject *o, struct fsObjectContainer *oc) {
420 UBYTE *endadr;
422 endadr=(UBYTE *)oc+globals->bytes_block-sizeof(struct fsObject)-2;
424 if((UBYTE *)o<endadr && o->name[0]!=0) {
425 return(TRUE);
427 return(FALSE);
432 BOOL checkobjectcontainerfornode(ULONG block, ULONG node) {
433 struct fsObjectContainer *oc=(struct fsObjectContainer *)buffer;
435 read2(block);
437 if(isblockvalid(oc,block,OBJECTCONTAINER_ID)!=FALSE) {
438 struct fsObject *o=oc->object;
440 while(isobject(o,oc)!=FALSE) {
441 if(BE2L(o->be_objectnode)==node) {
442 return(TRUE);
445 o=nextobject(o);
448 printf("ObjectContainer at block %ld doesn't contain node %ld\n",(long)block,(long)node);
449 return(FALSE);
452 printf("ObjectContainer at block %ld is invalid and doesn't contain node %ld\n",(long)block,(long)node);
453 return(FALSE);
458 BOOL checknodecontainers2(ULONG block, ULONG parent, ULONG nodenumber, ULONG nodes) {
459 struct fsNodeContainer *b;
461 // printf("Checking NodeContainer at block %ld, with parent %ld, nodenumber %ld and nodes %ld\n",block,parent,nodenumber,nodes);
463 if((b=AllocVec(globals->bytes_block, globals->bufmemtype))!=0) {
464 read2(block);
465 CopyMemQuick(buffer,b,globals->bytes_block);
467 if(isblockvalid(b,block,NODECONTAINER_ID)!=FALSE) {
468 if(BE2L(b->be_nodenumber)==nodenumber) {
469 if(nodes==0) {
470 nodes=BE2L(b->be_nodes);
473 if(BE2L(b->be_nodes)==nodes) {
474 if(nodes!=1) {
475 WORD maxnodes=(globals->bytes_block-sizeof(struct fsNodeContainer))/4;
476 LONG nodes2=nodes/maxnodes;
477 WORD n;
479 if(nodes2==0) {
480 nodes2=1;
483 for(n=0; n<maxnodes; n++) {
484 if(BE2L(b->be_node[n])!=0) {
485 if(checknodecontainers2(BE2L(b->be_node[n])>>shifts_block32, block, nodenumber, nodes2)==FALSE) {
486 FreeVec(b);
487 return(FALSE);
490 nodenumber+=nodes;
493 FreeVec(b);
494 return(TRUE);
496 else {
497 WORD maxnodes=(globals->bytes_block-sizeof(struct fsNodeContainer))/sizeof(struct fsObjectNode);
498 WORD n;
499 struct fsObjectNode *on=(struct fsObjectNode *)b->be_node;
501 for(n=0; n<maxnodes; n++) {
502 if(BE2L(on->node.be_data)!=0 && BE2L(on->node.be_data)!=-1) {
503 if(checkobjectcontainerfornode(BE2L(on->node.be_data),nodenumber+n)==FALSE) {
504 FreeVec(b);
505 return(FALSE);
510 else if(BE2L(on->node.be_data)==0 && (on->next!=0 || on->hash16!=0)) {
511 printf("NodeContainer at block %ld has a not fully cleared node.\n",block);
512 FreeVec(b);
513 return(FALSE);
517 on++;
520 FreeVec(b);
521 return(TRUE);
524 else {
525 printf("NodeContainer at block %ld has nodes %ld while it should be %ld.\n",(long)block,(long)BE2L(b->be_nodes),(long)nodes);
528 else {
529 printf("NodeContainer at block %ld has nodenumber %ld while it should be %ld.\n",(long)block,(long)BE2L(b->be_nodenumber),(long)nodenumber);
533 FreeVec(b);
535 else {
536 printf("ERROR: Out of memory!\n");
539 return(FALSE);
543 BOOL checknodecontainers(ULONG block) {
544 return(checknodecontainers2(block,0,1,0));
549 UBYTE *mark(LONG offset, LONG blocks) {
550 LONG result;
552 result=bmffo(bitmap, (globals->blocks_total+31)>>5, offset);
554 if(result!=((globals->blocks_total+31)&(~0x1f)) && result < offset+blocks) {
555 return(tostring("Block at offset %ld is already in use while marking %ld blocks from %ld.\n",result,blocks,offset));
558 if((result=bmset(bitmap, (globals->blocks_total+31)>>5, offset, blocks))!=blocks) {
559 return(tostring("Error while marking %ld blocks from %ld. Could only mark %ld blocks.\n",blocks,offset,result));
562 return(0);
567 LONG findnode(BLCK nodeindex,UWORD nodesize,NODE nodeno,struct fsNode **returned_node) {
568 LONG errorcode;
570 /* Finds a specific node by number. It returns the cachebuffer which contains the fsNode
571 structure and a pointer to the fsNode structure directly. */
573 while((errorcode=read2(nodeindex))==0) {
574 struct fsNodeContainer *nc=(struct fsNodeContainer *)buffer;
576 if(BE2L(nc->be_nodes)==1) {
577 /* We've descended the tree to a leaf NodeContainer */
579 *returned_node=(struct fsNode *)((UBYTE *)nc->be_node+nodesize*(nodeno-BE2L(nc->be_nodenumber)));
581 return(0);
583 else {
584 UWORD containerentry=(nodeno-BE2L(nc->be_nodenumber))/BE2L(nc->be_nodes);
586 nodeindex=BE2L(nc->be_node[containerentry])>>shifts_block32;
590 return(errorcode);
595 BOOL checkobjectcontainers2(ULONG block, ULONG previous, ULONG parent) {
596 struct fsObjectContainer *oc;
597 UBYTE *str;
599 if((oc=AllocVec(globals->bytes_block, globals->bufmemtype))!=0) {
600 do {
601 read2(block);
602 CopyMemQuick(buffer,oc,globals->bytes_block);
604 if(isblockvalid(oc,block,OBJECTCONTAINER_ID)!=FALSE) {
605 if(BE2L(oc->be_previous)==previous) {
606 if(BE2L(oc->be_parent)==parent) {
607 struct fsObject *o=oc->object;
608 struct fsObjectNode *node;
609 LONG errorcode;
611 while(isobject(o,oc)!=FALSE) {
613 if((errorcode=findnode(block_objectnodesbase, sizeof(struct fsObjectNode), BE2L(o->be_objectnode), (struct fsNode **)&node))==0) {
614 if(BE2L(node->node.be_data)==block) {
615 if((o->bits & OTYPE_LINK)==0) {
616 if((o->bits & OTYPE_DIR)!=0 && BE2L(o->object.dir.be_firstdirblock)!=0) {
617 if(checkobjectcontainers2(BE2L(o->object.dir.be_firstdirblock), 0, BE2L(o->be_objectnode))==FALSE) {
618 break;
621 else if((o->bits & OTYPE_DIR)==0) {
622 struct fsExtentBNode *ebn = NULL;
623 ULONG next=BE2L(o->object.file.be_data);
624 ULONG prev=0;
625 LONG errorcode;
627 while(next!=0) {
628 if((errorcode=findbnode(block_extentbnoderoot, next, (struct BNode **)&ebn))!=0) {
629 if(error("Errorcode %ld while locating BNode %ld of Object '%s' in ObjectContainer at block %ld.\n",errorcode,BE2L(o->object.file.be_data),o->name,block)) {
630 break;
634 if(BE2L(ebn->be_key)!=next) {
635 if(error("Error in Object '%s' in ObjectContainer at block %ld:\nBNode %ld has incorrect key. It is %ld while it should be %ld.\n",o->name,block,next,BE2L(ebn->be_key),next)) {
636 break;
640 if((prev!=0 && BE2L(ebn->be_prev)!=prev) || (prev==0 && BE2L(ebn->be_prev)!=(BE2L(o->be_objectnode) | 0x80000000))) {
641 if(error("Error in Object '%s' in ObjectContainer at block %ld:\nBNode %ld has incorrect previous. It is 0x%08lx.\n",o->name,block,next,BE2L(ebn->be_prev))) {
642 break;
646 if(BE2W(ebn->be_blocks)==0) {
647 if(error("Error in Object '%s' in ObjectContainer at block %ld:\nBNode %ld has a zero block count!\n",o->name,block,next)) {
648 break;
652 if((str=mark(BE2L(ebn->be_key), BE2W(ebn->be_blocks)))!=0) {
653 if(error("Error in Object '%s' in ObjectContainer at block %ld:\nBNode %ld points to space already in use:\n %s",o->name,block,next,str)) {
654 freestring(str);
655 break;
657 freestring(str);
660 prev=next;
661 next=BE2L(ebn->be_next);
664 if(next!=0) {
665 break;
670 else {
671 printf("Node %ld of Object in ObjectContainer at block %ld points to wrong block (%ld)\n",(long)BE2L(o->be_objectnode),(long)block,(long)BE2L(node->node.be_data));
672 break;
675 else {
676 printf("Error %ld occured while locating Node %ld of Object in ObjectContainer at block %ld.\n",(long)errorcode,(long)BE2L(o->be_objectnode),(long)block);
677 break;
680 o=nextobject(o);
683 if(isobject(o,oc)!=FALSE) {
684 break;
687 else {
688 printf("ObjectContainer at block %ld has parent %ld while it should be %ld.\n",(long)block,(long)BE2L(oc->be_parent),(long)parent);
689 break;
692 else {
693 printf("ObjectContainer at block %ld has previous %ld while it should be %ld.\n",(long)block,(long)BE2L(oc->be_previous),(long)previous);
694 break;
697 else {
698 break;
701 previous=block;
702 block=BE2L(oc->be_next);
703 } while(block!=0);
705 FreeVec(oc);
707 if(block==0) {
708 return(TRUE);
711 else {
712 printf("ERROR: Out of memory!\n");
715 return(FALSE);
720 BOOL checkobjectcontainers(ULONG block) {
721 return(checkobjectcontainers2(block,0,0));
726 void dumpblock(ULONG block, void *data, ULONG bytes) {
727 ULONG *d=(ULONG *)data;
728 UBYTE *d2=(UBYTE *)data;
729 UWORD off=0;
730 UBYTE s[40];
732 if(bytes<globals->bytes_block) {
733 printf("Dump of first %ld bytes of block %ld.\n",(long)bytes,(long)block);
735 else {
736 printf("Dump of block %ld.\n",(long)block);
739 while(bytes>0) {
740 WORD n;
741 UBYTE c;
742 UBYTE *s2;
744 n=16;
745 s2=s;
747 while(--n>=0) {
748 c=*d2++;
750 if(c<32) {
751 c+=64;
753 if(c>=127 && c<=160) {
754 c='.';
757 *s2++=c;
759 *s2=0;
761 printf("0x%04lx: %08lx %08lx %08lx %08lx %s\n",(unsigned long)off,(unsigned long)BE2L(d[0]),(unsigned long)BE2L(d[1]),(unsigned long)BE2L(d[2]),(unsigned long)BE2L(d[3]),s);
763 bytes-=16;
764 d+=4;
765 off+=16;
771 BOOL checkadminspacecontainers(ULONG block) {
772 struct fsAdminSpaceContainer *asc;
774 if((asc=AllocVec(globals->bytes_block, globals->bufmemtype))!=0) {
775 ULONG previous=0;
777 while(block!=0) {
778 read2(block);
779 CopyMemQuick(buffer,asc,globals->bytes_block);
781 if(isblockvalid(asc,block,ADMINSPACECONTAINER_ID)!=FALSE) {
782 if(BE2L(asc->be_previous)==previous) {
783 // if(asc->bits==32) {
784 struct fsAdminSpace *as=asc->adminspace;
786 while((UBYTE *)as<((UBYTE *)asc+globals->bytes_block) && BE2L(as->be_space)!=0) {
787 ULONG adminblock=BE2L(as->be_space);
788 LONG bits=BE2L(as->be_bits);
789 WORD n=32;
790 BYTE valid;
791 UBYTE *str;
793 if((str=mark(adminblock,32))!=0) {
794 if(error("AdminSpaceContainer at %ld occupies already used space:\n %s",block,str)) {
795 freestring(str);
796 break;
798 freestring(str);
801 while(--n>=0) {
802 if(bits<0) {
803 struct fsBlockHeader *bh=(struct fsBlockHeader *)buffer;
805 read2(adminblock);
807 valid=FALSE;
808 if(checkchecksum((UBYTE *)bh)!=FALSE) {
809 if(bh->id==ADMINSPACECONTAINER_ID || bh->id==OBJECTCONTAINER_ID || bh->id==HASHTABLE_ID || bh->id==NODECONTAINER_ID || bh->id==BNODECONTAINER_ID || bh->id==TRANSACTIONOK_ID || bh->id==SOFTLINK_ID) {
810 if(BE2L(bh->be_ownblock)==adminblock) {
811 valid=TRUE;
816 if(valid==FALSE) {
817 printf("Block %ld is not a valid admin block but it is marked in use in AdminSpaceContainer at %ld\n",(long)adminblock,(long)block);
818 dumpblock(adminblock,buffer,64);
819 break;
822 bits<<=1;
823 adminblock++;
826 if(n>=0) {
827 break;
830 as++;
833 if((UBYTE *)as<((UBYTE *)asc+globals->bytes_block) && BE2L(as->be_space)!=0) {
834 break;
837 // }
838 // else {
839 // printf("AdminSpaceContainer at block %ld hasn't got 32 blocks/entry (%ld)!\n",block,asc->bits);
840 // break;
841 // }
843 else {
844 printf("AdminSpaceContainer at block %ld has previous %ld while it should be %ld.\n",(long)block,(long)BE2L(asc->be_previous),(long)previous);
845 break;
848 else {
849 break;
852 previous=block;
853 block=BE2L(asc->be_next);
856 FreeVec(asc);
858 if(block==0) {
859 return(TRUE);
862 else {
863 printf("ERROR: Out of memory!\n");
866 return(FALSE);
871 void sfscheck(void) {
872 ULONG block_bitmapbase;
873 ULONG block_adminspacecontainer;
875 printf("\n");
876 printf("Checking RootBlocks\n");
878 read2(globals->blocks_total-1);
880 if((checkrootblock((struct fsRootBlock *)buffer,globals->blocks_total-1))!=FALSE) {
882 read2(0);
884 if((checkrootblock((struct fsRootBlock *)buffer,0))!=FALSE) {
885 struct fsRootBlock *b=(struct fsRootBlock *)buffer;
886 UBYTE *str;
888 printf("...okay\n");
890 block_bitmapbase=BE2L(b->be_bitmapbase);
891 block_root=BE2L(b->be_rootobjectcontainer);
892 block_extentbnoderoot=BE2L(b->be_extentbnoderoot);
893 block_adminspacecontainer=BE2L(b->be_adminspacecontainer);
894 block_objectnodesbase=BE2L(b->be_objectnoderoot);
896 if((str=mark(block_bitmapbase,blocks_bitmap))!=0) {
897 Printf("Error while marking bitmap space:\n %s",str);
898 freestring(str);
901 printf("Checking AdminSpaceContainers at block %ld\n",(long)block_adminspacecontainer);
902 if((checkadminspacecontainers(block_adminspacecontainer))!=FALSE) {
903 printf("...okay\n");
905 printf("Checking NodeContainers at block %ld\n",(long)block_objectnodesbase);
906 if((checknodecontainers(block_objectnodesbase))!=FALSE) {
907 printf("...okay\n");
909 printf("Checking ObjectContainers at block %ld\n",(long)block_root);
910 if((checkobjectcontainers(block_root))!=FALSE) {
911 printf("...okay\n");
913 printf("Checking Bitmap at block %ld (%ld blocks, %ld bits/bitmap)\n",(long)block_bitmapbase,(long)blocks_bitmap,(long)blocks_inbitmap);
914 if((checkbitmap(block_bitmapbase))!=FALSE) {
915 printf("...okay\n");
918 else {
919 returncode=20;
920 printf("...damaged\n");
923 else {
924 returncode=20;
925 printf("...damaged\n");
928 else {
929 returncode=20;
930 printf("...damaged\n");
933 else {
934 returncode=20;
935 printf("...damaged\n");
938 else {
939 returncode=20;
940 printf("...damaged\n");
943 else {
944 returncode=20;
945 printf("...damaged\n");
949 if(errors!=0) {
950 returncode=20;
956 struct BNode *searchforbnode(ULONG key,struct BTreeContainer *tc) {
957 struct BNode *tn;
958 WORD n=BE2W(tc->be_nodecount)-1;
960 tn=(struct BNode *)((UBYTE *)tc->bnode+n*tc->nodesize);
962 for(;;) {
963 if(n<=0 || key >= BE2L(tn->be_key)) {
964 return(tn);
966 tn=(struct BNode *)((UBYTE *)tn-tc->nodesize);
967 n--;
973 LONG findbnode(BLCK rootblock,ULONG key,struct BNode **returned_bnode) {
974 LONG errorcode;
976 while((errorcode=read2(rootblock))==0) {
977 struct fsBNodeContainer *bnc=(struct fsBNodeContainer *)buffer;
978 struct BTreeContainer *btc=&bnc->btc;
980 *returned_bnode=searchforbnode(key,btc);
981 if(btc->isleaf==TRUE) {
982 break;
984 rootblock=BE2L((*returned_bnode)->be_data);
987 return(errorcode);
992 void freestring(UBYTE *str) {
993 if(str!=emptystring) {
994 FreeVec(str);
1000 UBYTE *tostring(UBYTE *fmt, ... ) {
1001 UBYTE *buf;
1003 if((buf=AllocVec(200,MEMF_CLEAR))!=0) {
1004 AROS_SLOWSTACKFORMAT_PRE(fmt);
1006 RawDoFmt(fmt,AROS_SLOWSTACKFORMAT_ARG(fmt),RAWFMTFUNC_STRING,buf);
1008 AROS_SLOWSTACKFORMAT_POST(fmt);
1009 return(buf);
1011 else {
1012 return(emptystring);
1018 BOOL error(UBYTE *fmt, ... ) {
1020 AROS_SLOWSTACKFORMAT_PRE(fmt);
1021 VPrintf(fmt,AROS_SLOWSTACKFORMAT_ARG(fmt));
1022 AROS_SLOWSTACKFORMAT_POST(fmt);
1024 errors++;
1026 if(errors>maxerrors) {
1027 return(TRUE);
1030 return(FALSE);
1034 #if 0
1035 /* cachedio.o already implements this function, so the
1036 dummy function below is not needed. */
1038 LONG getbuffer(UBYTE **tempbuffer, ULONG *maxblocks) {
1040 /* Used by deviceio.o to get a piece of memory which it can
1041 use for buffering transfers when the Mask prevents a
1042 direct transfer.
1044 You must return 0, a pointer to the buffer and the number
1045 of blocks (each /bytes_block/ bytes in size) you allocated.
1046 For the purpose of SFScheck this function is probably never
1047 called since all our buffers are atleast LONG aligned and
1048 allocated with the correct bufmemtype. */
1050 return(ERROR_NO_FREE_STORE);
1053 #endif
1056 void starttimeout(void) {
1057 /* Called by deviceio.o each time there is a physical
1058 disk access. You can use this to start a timer and
1059 call motoroff() when the disk hasn't been accessed
1060 for a specific amount of time (SFS uses 1 second).
1062 SFScheck doesn't use this function. */