2 * $Log: standardscan.c $
3 * Revision 2.10 1999/09/11 16:45:50 Michiel
4 * Versie 1.5 with Unformat and Repair nodos
6 * Revision 2.9 1999/09/10 22:14:49 Michiel
9 * Revision 2.8 1999/08/01 10:48:21 Michiel
12 * Revision 2.7 1999/05/28 05:07:33 Michiel
13 * Fixed bug occuring on empty directory blocks
14 * Added rbl.always fix; improved rbl.disksize fix
17 * Revision 2.6 1999/05/17 10:32:39 Michiel
18 * long filename support, verbose fixes
20 * Revision 2.5 1999/05/17 09:27:11 Michiel
22 * made verbose less verbose
24 * Revision 2.4 1999/05/07 16:49:00 Michiel
27 * Revision 2.3 1999/05/04 17:59:09 Michiel
28 * check mode, logfile, search rootblock implemented
31 * Revision 2.1 1999/04/30 12:17:58 Michiel
32 * Accepts OK disks, bitmapfix and hardlink fix works
34 * Revision 1.2 1999/04/22 15:23:50 Michiel
37 * Revision 1.1 1999/04/19 22:16:53 Michiel
42 #include <exec/types.h>
43 #include <exec/ports.h>
44 #include <devices/trackdisk.h>
45 #include <libraries/asl.h>
46 #include <dos/dosextens.h>
47 #include <dos/filehandler.h>
53 #include <proto/asl.h>
54 #include <proto/exec.h>
58 long __stack
= 30*1024;
59 extern struct Window
*CheckRepairWnd
;
61 /**************************************
63 **************************************/
68 uint32 flags
; /* internal flags */
69 uint32 opties
; /* options */
74 enum {syntax
, resbitmap
, mainbitmap
, anodebitmap
, finished
} stage
;
76 struct MinList
*doubles
;
81 rootblock_t
*rbl
= NULL
;
82 c_extensionblock_t rext
= { 0 };
84 bool aborting
= 0; // used by break trap
86 /**************************************
88 **************************************/
90 static error_t
mainStandardScan(uint32 flags
);
91 static error_t
exitStandardScan(error_t error
);
92 static error_t
ss_CheckDirTree(void);
93 static error_t
vol_CheckBlockNr(ULONG
*blocknr
);
94 static error_t
GetRootBlock(void);
95 static error_t
CheckRootBlock(void);
96 static error_t
GetRext(void);
97 static error_t
RepairBootBlock(void);
98 static error_t
RepairDeldir(void);
99 static bool dd_CheckBlock(uint32 bloknr
, int seqnr
);
100 static error_t
RepairDirTree(void);
101 static error_t
RepairDir(struct direntry
*de
, c_dirblock_t
*parent
);
102 static error_t
RepairDirBlock(uint32 bloknr
, uint32 anodenr
, uint32 parent
);
103 static error_t
RepairDirEntry(struct direntry
*de
, c_dirblock_t
*dirblk
);
104 static error_t
RepairFile(struct direntry
*de
, c_dirblock_t
*parent
);
105 static error_t
RepairHardLink(struct direntry
*de
, c_dirblock_t
*dirblok
);
106 static error_t
RepairSoftLink(struct direntry
*de
, c_dirblock_t
*dirblok
);
107 static error_t
RepairRollover(struct direntry
*de
, c_dirblock_t
*dirblok
);
108 static error_t
RemoveDirEntry(struct direntry
*de
, c_dirblock_t
*dirblk
);
109 static error_t
DeleteAnode(uint32 anodechain
, uint32 node
);
110 static error_t
GetExtraFields(struct extrafields
*extrafields
, struct direntry
*de
);
111 static error_t
SetExtraFields(struct extrafields
*extrafields
, struct direntry
*from
, c_dirblock_t
*dirblk
);
112 static error_t
RepairLinkChain(struct direntry
*de
, c_dirblock_t
*dirblk
);
113 static error_t
CheckAnode(canode_t
*anode
, uint32 nr
, bool fix
);
114 static error_t
RepairAnodeTree(void);
115 static error_t
RepairBitmapTree(void);
116 static error_t
InitReservedBitmap(void);
117 static error_t
InitAnodeBitmap(void);
118 static error_t
InitMainBitmap(void);
119 static error_t
RepairReservedBitmap(void);
120 static error_t
RepairMainBitmap(void);
121 static error_t
RepairAnodeBitmap(void);
122 static error_t
MainBlockUsed(uint32 bloknr
);
123 static error_t
AnodeUsed(uint32 bloknr
);
124 static error_t
bg_ItemUsed(bitmap_t
*bm
, uint32 nr
);
125 static BOOL
IsAnodeUsed(uint32 nr
);
126 static uint32
vol_SearchFileSystem(void);
127 static bitmap_t
*bg_InitBitmap(int32 start
, int32 stop
, int32 step
);
128 static void bg_KillBitmap(bitmap_t
**bm
);
129 static BOOL
bg_IsItemUsed(bitmap_t
*bm
, uint32 nr
);
130 int SearchInDir(uint32 diranodenr
, uint32 target
);
131 static void AddExtraFields(struct direntry
*direntry
, struct extrafields
*extra
);
132 static bool MakeMountFile(char *fname
);
133 static error_t
BuildRootBlock_hub(void);
135 /**************************************
137 **************************************/
146 void __regargs
__chkabort(void)
148 /* Check & clear CTRL_C signal */
149 if(SetSignal(0L,SIGBREAKF_CTRL_C
) & SIGBREAKF_CTRL_C
)
156 static BOOL
FileSizeCheck(ULONG low
, ULONG high
, ULONG numblocks
)
161 low
+= volume
.blocksize
- 1;
164 size
= low
>> volume
.blockshift
;
165 size
|= high
<< (32 - volume
.blockshift
);
166 if (size
== numblocks
)
171 /**************************************
173 **************************************/
176 error_t
StandardScan(uint32 opties
)
182 memset(&ss
, sizeof(ss
), 0);
186 if (opties
& (SSF_CHECK
|SSF_FIX
))
187 flags
|= SSF_GEN_BMMASK
;
190 memset(&stats
, 0, sizeof(stats
));
191 return mainStandardScan(flags
);
195 static error_t
mainStandardScan(uint32 flags
)
199 volume
.showmsg("Initializing\n");
202 ss
.pass
= stats
.pass
= 1;
203 ss
.verbose
= flags
& SSF_VERBOSE
;
204 ss
.unformat
= flags
& SSF_UNFORMAT
;
211 mode
= repair
; // !! niet really correct !! fix this
212 volume
.showmsg("Unformatting...\n");
213 if (!(rbl
= (rootblock_t
*)AllocBufMem (MAXRESBLOCKSIZE
)))
215 adderror("couldn't allocate memory for rootblock");
216 return exitStandardScan(e_out_of_memory
);
218 if ((error
= BuildRootBlock_hub()) || aborting
)
219 return exitStandardScan(error
);
223 volume
.status(0, "rootblock", 100);
224 if ((error
= GetRootBlock()) || aborting
)
225 return exitStandardScan(error
);
227 volume
.progress(0, 40);
228 if ((error
= RepairBootBlock()) || aborting
)
229 return exitStandardScan(error
);
231 /* after the rootblock and bootblock the boundaries of the partition are known
234 /* read rootblockextension */
235 volume
.progress(0, 30);
236 rext
.data
= calloc(1, SIZEOF_RESBLOCK
);
238 if ((error
= GetRext()) || aborting
)
239 return exitStandardScan(error
);
241 GetPFS2Revision(bericht
);
242 volume
.showmsg("Disk formatted with ");
243 volume
.showmsg(bericht
);
244 volume
.showmsg("\n");
247 volume
.progress(0, 30);
248 while (ss
.stage
!= finished
&& ss
.pass
< MAX_PASS
)
250 stats
.pass
= ss
.pass
;
251 sprintf(bericht
, "Starting pass %d\n", ss
.pass
);
252 volume
.showmsg(bericht
);
253 volume
.updatestats();
254 if (mode
== check
&& stats
.numerrors
> 0)
256 error
= ss_CheckDirTree();
257 if ((error
!= e_none
) || aborting
)
258 return exitStandardScan(error
);
264 if (ss
.stage
!= finished
)
265 return e_max_pass_exceeded
;
267 volume
.status(0, "finishing up", 2);
268 volume
.progress(0, 1);
269 exitStandardScan(e_none
);
270 volume
.progress(0, 1);
274 static error_t
exitStandardScan(error_t error
)
284 if (rext
.mode
== check
)
288 KillReservedBitmap();
293 if ((error
!= e_none
) || aborting
)
294 volume
.showmsg("ABORTED\n");
295 else if (ss
.unformat
)
298 "Disk has been unformatted. Unformatting can\n"
299 "cause problems later. Therefor we recommend\n"
300 "to format this partition after backing up \n"
301 "all data\n", "OK", NULL
);
307 /* main loop: check the partition defined by the rootblock and
308 * rext (rootblock extension)
310 static error_t
ss_CheckDirTree(void)
313 int newpassneeded
= 0;
322 /* initialize reserved bitmap generation */
323 if (ss
.flags
& SSF_GEN_RESBITMAP
)
324 InitReservedBitmap();
326 if (rext
.mode
== check
)
327 if ((error
= ResBlockUsed(rext
.blocknr
)))
330 /* anode blok tree */
331 /* if anodeindexblok faulty --> create (using DiskScan) */
332 if ((error
= RepairAnodeTree()) || aborting
)
336 /* check syntax bitmap tree
337 * if block faulty --> create, kill bitmap, ss_makebm = false
339 if ((error
= RepairBitmapTree()) || aborting
)
344 if (ss
.flags
& SSF_GEN_MAINBITMAP
)
349 if (ss
.flags
& SSF_GEN_ANODEBITMAP
)
358 if ((error
= RepairDeldir()) || aborting
)
362 if ((error
= RepairDirTree()) || aborting
)
365 /* on hardlink conflict */
377 /* need another pass if blocks were created
378 * (should not be necessary!!)
380 if (!IsMinListEmpty(&volume
.buildblocks
))
383 /* allocating created blocks & reparing reserved bitmap can only
384 * be done after the reserved bitmap has been generated.
385 * ss.flags is set to false if generation was aborted.
387 if (IsBitmapValid(volume
.resbitmap
))
389 if ((error
= AllocBuildBlocks()))
392 if ((error
= RepairReservedBitmap()) || aborting
)
397 if (ss
.stage
< resbitmap
)
399 ss
.stage
= resbitmap
;
403 return e_res_bitmap_fail
; /* fatal error */
412 /* bitmap generatie has been aborted (disabled during scan)
413 * generate main and anodebitmap
415 if (!IsBitmapValid(volume
.mainbitmap
))
417 if (ss
.stage
< mainbitmap
)
419 ss
.stage
= mainbitmap
;
423 return e_main_bitmap_fail
; /* fatal error */
426 if (!IsBitmapValid(volume
.anodebitmap
))
428 if (ss
.stage
< anodebitmap
)
430 ss
.stage
= anodebitmap
;
434 return e_anode_bitmap_fail
;
437 if ((error
= RepairMainBitmap()) || aborting
)
440 if ((error
= RepairAnodeBitmap()) || aborting
)
449 ss
.stage
= mainbitmap
;
452 /* Need another pass if blocks build (created) during
453 * scan. Calling allocbuildblocks here is pointless;
454 * the reserved bitmap is not valid because of invalid blocks,
455 * possibly during non reserved bitmap phase!
457 if (!IsMinListEmpty(&volume
.buildblocks
))
458 ss
.stage
= resbitmap
;
464 /**************************************
466 **************************************/
468 /* functions for in cache struct
469 * gets block from reserved area and checks partition
474 * block_outside_reserved
475 * block_outside_partition
478 /* check if a block is in partition range */
479 static error_t
vol_CheckBlockNr(ULONG
*blocknr
)
481 if (*blocknr
> volume
.lastreserved
) {
483 adderror("block outside reserved area");
484 return e_block_outside_reserved
;
487 *blocknr
+= volume
.firstblock
;
488 if (*blocknr
> volume
.lastblock
|| *blocknr
< volume
.firstblock
) {
490 adderror("block outside partition");
491 return e_block_outside_partition
;
498 error_t
vol_GetBlock(cachedblock_t
*blok
, ULONG bloknr
)
504 if ((error
= vol_CheckBlockNr(&realbloknr
)))
507 if ((error
= c_GetBlock((uint8
*)blok
->data
, realbloknr
, SIZEOF_RESBLOCK
)))
514 blok
->blocknr
= bloknr
;
519 error_t
vol_WriteBlock(cachedblock_t
*blok
)
524 if (blok
->mode
!= build
)
526 bloknr
= blok
->blocknr
;
527 if ((status
= vol_CheckBlockNr(&bloknr
)))
530 return c_WriteBlock((uint8
*)blok
->data
, bloknr
, SIZEOF_RESBLOCK
);
537 /**************************************
539 **************************************/
543 static error_t
BuildRootBlock_hub(void)
548 "Press ok to rebuild rootblock or cancel to exit\n"
549 "WARNING: make sure correct accessmode (direct-scsi/td64/nsd)\n"
550 "is selected", "ok", "cancel"))
552 if (!(error
= BuildRootBlock(rbl
)))
554 fixederror("new rootblock build");
555 c_WriteBlock((uint8
*)rbl
, ROOTBLOCK
+ volume
.firstblock
, volume
.blocksize
);
564 /* read from disk and check
565 * Returns error (0 = ERROR_NONE = ok).
567 static error_t
GetRootBlock(void)
569 error_t error
= e_none
;
572 struct FileRequester
*freq
;
573 char mfname
[FNSIZE
], *t
;
576 enterblock(ROOTBLOCK
);
577 volume
.showmsg("Checking rootblock\n");
581 if (!(rbl
= (rootblock_t
*)AllocBufMem (MAXRESBLOCKSIZE
)))
583 adderror("couldn't allocate memory for rootblock");
584 return e_out_of_memory
;
588 if ((error
= c_GetBlock ((uint8
*)rbl
, ROOTBLOCK
+ volume
.firstblock
, volume
.blocksize
)))
590 adderror("rootblock could not be loaded");
594 // check rootblock type
595 if (!IsRootBlock(rbl
))
597 adderror("not an AFS, PFS-II or PFS-III disk");
598 okuser
= volume
.askuser("Rootblock not found.\n"
599 "Select ok to search for misplaced rootblock.", "ok", "cancel");
601 if (okuser
&& (bloknr
= vol_SearchFileSystem()))
603 volume
.showmsg("\nRootblock found. Repartitioning .. \n");
604 if ((error
= Repartition(bloknr
)))
608 "Partition is misplaced. Probable cause of this problem\n"
609 "is the use of the 'Get Drive Definition' option in\n"
610 "HDToolbox after the disk was formatted\n\n"
611 "Now a mountfile will be needed to mount the partition.\n"
612 "Press CONTINUE to select location to store the\n"
613 "mountlist", "CONTINUE", NULL
);
615 freq
= AllocAslRequestTags(ASL_FileRequest
, ASLFR_SleepWindow
, TRUE
,
616 ASLFR_TitleText
, "Select mountfile", ASLFR_InitialFile
, "mountme",
617 ASLFR_InitialDrawer
, "df0:", ASLFR_DoSaveMode
, TRUE
, TAG_DONE
);
621 if (AslRequestTags(freq
, ASLFR_Window
, CheckRepairWnd
, TAG_DONE
))
623 t
= stpcpy(mfname
, freq
->fr_Drawer
);
624 t
= stpcpy(t
, freq
->fr_File
);
625 if ((ok
= MakeMountFile(mfname
)))
626 volume
.showmsg("Mountlist written\n");
630 volume
.showmsg("no mountlist written\n");
634 FreeAslRequest(freq
);
635 volume
.askuser("Now starting to check/repair\n"
636 "relocated partition", "CONTINUE", NULL
);
638 return GetRootBlock();
642 okuser
= volume
.askuser("Rootblock not found.\n"
643 "Select ok to build a new one.\n"
644 "WARNING: Make sure this is a PFS partition.\n"
645 "Non-PFS disks will be destroyed by this operation\n",
649 return BuildRootBlock_hub();
658 error
= CheckRootBlock();
666 if ((error
= Repartition(volume
.firstblock
+ROOTBLOCK
)))
670 "The partition information stored in the RDB does\n"
671 "not match the partition information used when the\n"
672 "disk was formatted. Probable cause of this problem\n"
673 "is the use of the 'Get Drive Definition' option in\n"
674 "HDToolbox after the disk was formatted\n\n"
675 "Now a mountfile will be needed to mount the partition.\n"
676 "Press CONTINUE to select location to store the\n"
677 "mountlist", "CONTINUE", NULL
);
679 freq
= AllocAslRequestTags(ASL_FileRequest
, ASLFR_SleepWindow
, TRUE
,
680 ASLFR_TitleText
, "Select mountfile", ASLFR_InitialFile
, "mountme",
681 ASLFR_InitialDrawer
, "df0:", ASLFR_DoSaveMode
, TRUE
, TAG_DONE
);
685 if (AslRequestTags(freq
, ASLFR_Window
, CheckRepairWnd
, TAG_DONE
))
687 t
= stpcpy(mfname
, freq
->fr_Drawer
);
688 t
= stpcpy(t
, freq
->fr_File
);
689 if ((ok
= MakeMountFile(mfname
)))
690 volume
.showmsg("Mountlist written\n");
694 volume
.showmsg("no mountlist written\n");
698 FreeAslRequest(freq
);
699 volume
.askuser("Now starting to check/repair\n"
700 "redefined partition", "CONTINUE", NULL
);
702 return GetRootBlock();
704 case e_options_error
:
708 return BuildRootBlock_hub();
715 static bool MakeMountFile(char *fname
)
719 if ((mf
= fopen(fname
, "w")))
721 fprintf(mf
, "/****************************************/\n");
722 fprintf(mf
, "/* PFSDoctor generated mountlist */\n");
723 fprintf(mf
, "/****************************************/\n");
724 fprintf(mf
, "REPAIRED:\n");
725 fprintf(mf
, "\tDevice = %s\n", volume
.execdevice
);
726 fprintf(mf
, "\tUnit = %d\n", volume
.execunit
);
727 fprintf(mf
, "\tBuffers = 300\n");
728 fprintf(mf
, "\tBufMemType = %lu\n", volume
.dosenvec
->de_BufMemType
);
729 fprintf(mf
, "\tFlags = %lu\n", volume
.fssm
->fssm_Flags
);
730 fprintf(mf
, "\tDosType = %#lx\n", volume
.dosenvec
->de_DosType
);
731 fprintf(mf
, "\tGlobVec = -1\n");
732 fprintf(mf
, "\tInterleave = %ld\n", volume
.dosenvec
->de_Interleave
);
733 fprintf(mf
, "\tReserved = 2\n");
734 fprintf(mf
, "\tLowCyl = %lu\n", volume
.firstblock
);
735 fprintf(mf
, "\tHighCyl = %lu\n", volume
.lastblock
);
736 fprintf(mf
, "\tMount = 1\n");
737 fprintf(mf
, "\tSurfaces = 1\n");
738 fprintf(mf
, "\tBlocksPerTrack = 1\n");
739 fprintf(mf
, "\tPriority = 10\n");
740 fprintf(mf
, "\tStackSize = 600\n");
741 fprintf(mf
, "\tMaxTransfer = %lu\n", volume
.dosenvec
->de_MaxTransfer
);
742 fprintf(mf
, "\tMask = %#lx\n", volume
.dosenvec
->de_Mask
);
749 static uint32
vol_SearchFileSystem(void)
751 return SearchFileSystem(
752 (volume
.firstblock
> 1024) ? volume
.firstblock
- 1024 : 0,
753 volume
.firstblock
+ 1024);
756 bool IsRootBlock(rootblock_t
*r
)
760 // check rootblock type
761 if (r
->disktype
!= ID_PFS_DISK
&& r
->disktype
!= ID_PFS2_DISK
) {
763 volume
.showmsg("Unexpected rootblock id 0x%08lx\n", r
->disktype
);
768 // require non-null options to accept rootblock as such,
769 // otherwise it could be a bootblock
770 modemask
= MODE_HARDDISK
+ MODE_SPLITTED_ANODES
+ MODE_DIR_EXTENSION
;
771 if ((r
->options
& modemask
) != modemask
) {
773 volume
.showmsg("Unexpected rootblock options 0x%08lx\n", r
->options
);
781 /* check loaded rootblock
783 static error_t
CheckRootBlock(void)
787 ULONG modemask
, resblocksize
;
789 modemask
= MODE_HARDDISK
+ MODE_SPLITTED_ANODES
+ MODE_DIR_EXTENSION
790 + MODE_DELDIR
+ MODE_SIZEFIELD
+ MODE_EXTENSION
+ MODE_DATESTAMP
791 + MODE_SUPERINDEX
+ MODE_SUPERDELDIR
+ MODE_EXTROVING
+ MODE_LONGFN
794 if (rbl
->options
& ~modemask
)
796 adderror("Unknown options enabled. Ask for an upgrade.");
797 return e_options_error
;
801 if (!rbl
->diskname
[0])
804 adderror("volume has no name");
807 fixederror("volume had no name");
808 rbl
->diskname
[0] = strlen("doctor");
809 strcpy((char *)&rbl
->diskname
[1], "doctor");
814 strncpy (volume
.diskname
, (char *)&rbl
->diskname
[1], rbl
->diskname
[0]);
815 volume
.diskname
[rbl
->diskname
[0]+1] = 0;
816 volume
.showmsg("Checking disk ");
817 volume
.showmsg(volume
.diskname
);
818 volume
.showmsg("\n");
819 volume
.showmsg("Reserved blocksize: %lu\n", rbl
->reserved_blksize
);
822 if (rbl
->disktype
== ID_PFS2_DISK
) {
823 if (volume
.disksize
> MAXDISKSIZE4K
) {
824 adderror("too large (>1.6TB) partition size");
825 return e_options_error
;
827 if (volume
.disksize
> MAXDISKSIZE1K
) {
829 if (volume
.disksize
> MAXDISKSIZE2K
)
833 if (volume
.disksize
> MAXDISKSIZE1K
) {
834 adderror("too large (>104GB) partition size");
835 return e_options_error
;
839 if (rbl
->reserved_blksize
!= resblocksize
)
841 if (rbl
->reserved_blksize
== 1024 || rbl
->reserved_blksize
== 2048 || rbl
->reserved_blksize
== 4096) {
842 adderror("reserved blocksize is valid but does not match partition size. Driver size limit problem?");
843 return e_options_error
;
845 sprintf(bericht
, "wrong reserved blocksize of %d", rbl
->reserved_blksize
);
847 rbl
->reserved_blksize
= resblocksize
;
851 volume
.rescluster
= resblocksize
/ volume
.blocksize
;
853 // size must match, else repartition
854 if (rbl
->options
& MODE_SIZEFIELD
)
856 if(rbl
->disksize
!= volume
.disksize
)
860 /* uses rule: if difference less then 10%, assume mistake
861 * in RDB, otherwise assume mistake in rootblock
863 adderror("wrong disksize");
864 volume
.showmsg("Rootblock size: %lu, driver reported size: %lu\n", rbl
->disksize
, volume
.disksize
);
865 difference
= abs((int32
)rbl
->disksize
- (int32
)volume
.disksize
);
866 if (difference
< volume
.disksize
/10)
868 error
= e_repartition
;
870 else if (mode
!= check
)
872 rbl
->disksize
= volume
.disksize
;
874 fixederror("set disksize");
879 if (rbl
->alwaysfree
< volume
.disksize
/40 ||
880 rbl
->alwaysfree
> volume
.disksize
/15)
882 fixederror("allocation block buffer out of range");
883 rbl
->alwaysfree
= volume
.disksize
/20;
888 return c_WriteBlock((uint8
*)rbl
, ROOTBLOCK
+ volume
.firstblock
, volume
.blocksize
);
894 /**************************************
895 * GetRootBlockExtension
896 **************************************/
898 /* check rootblock extension. Do 'easy fix'. Returns
901 static error_t
GetRext(void)
904 uint32 bloknr
, oldbloknr
;
906 bloknr
= rbl
->extension
;
908 volume
.showmsg("Checking rext\n");
912 if ((error
= volume
.getblock((cachedblock_t
*)&rext
, bloknr
)))
916 if (!bloknr
|| rext
.data
->id
!= EXTENSIONID
)
918 adderror("extension block has wrong id");
921 volume
.status(1, "Searching rext", 256);
923 bloknr
= SearchBlock(EXTENSIONID
, 0, bloknr
, 0, 0, 0);
926 sprintf(bericht
, "replaced block %lu with backup %lu", oldbloknr
, bloknr
);
928 rbl
->extension
= bloknr
;
933 volume
.showmsg("No replacement block found\n");
935 if ((error
= BuildRext(&rext
)))
936 adderror("building new rootblockextension failed");
938 fixederror("new rootblockextension created");
944 return e_fatal_error
;
948 // ResBlockUsed(bloknr); in initreservedbitmap
950 /* check if enabled */
951 if (!(rbl
->options
& MODE_EXTENSION
))
953 rbl
->options
|= MODE_EXTENSION
;
954 volume
.writeblock((cachedblock_t
*)&rext
);
956 adderror("MODE_EXTENSION is disabled");
958 fixederror("MODE_EXTENSION was disabled");
962 if (rbl
->options
& MODE_LONGFN
)
964 if (rext
.data
->fnsize
< 30 || rext
.data
->fnsize
> 108)
966 sprintf(bericht
, "illegal filename size of %d", rext
.data
->fnsize
);
971 if (rext
.data
->fnsize
< 30)
973 fixederror("reset filename size to 30");
974 rext
.data
->fnsize
= 30;
978 fixederror("reset filename size to 100");
979 rext
.data
->fnsize
= 100;
981 volume
.writeblock((cachedblock_t
*)&rext
);
984 volume
.fnsize
= rext
.data
->fnsize
- 1;
988 volume
.fnsize
= 32 - 1;
992 if (rext
.data
->postponed_op
[0] ||
993 rext
.data
->postponed_op
[1] ||
994 rext
.data
->postponed_op
[2] ||
995 rext
.data
->postponed_op
[3])
998 adderror("rootblock extension TBD not empty");
1001 rext
.data
->postponed_op
[0] =
1002 rext
.data
->postponed_op
[1] =
1003 rext
.data
->postponed_op
[2] =
1004 rext
.data
->postponed_op
[3] = 0;
1005 volume
.writeblock((cachedblock_t
*)&rext
);
1006 fixederror("rootblock extension TBD not empty");
1015 /* check loaded rootblock extension
1017 bool GetPFS2Revision(char *vstring
)
1020 uint16 ver
= rext
.data
->pfs2version
>> 16;
1021 uint16 rev
= rext
.data
->pfs2version
& 0xffff;
1033 strcpy(buf
, "PFS-II");
1035 strcpy(buf
, "PFS-III");
1037 strcpy(buf
, "PFS-II");
1039 sprintf(vstring
, "%s %d.%d", buf
, ver
, rev
);
1046 /**************************************
1048 **************************************/
1050 /* read and check bootblock (not store)
1052 static error_t
RepairBootBlock(void)
1055 cachedblock_t bootbl
;
1057 enterblock(BOOTBLOCK
);
1060 bootbl
.data
= calloc(1, MAXRESBLOCKSIZE
);
1061 if ((error
= volume
.getblock ((cachedblock_t
*)&bootbl
, BOOTBLOCK
)))
1063 adderror("bootblock could not be loaded");
1068 // check bootblock type
1069 if (bootbl
.data
->bootblock
.disktype
!= ID_PFS_DISK
)
1072 adderror("bootblock has wrong ID");
1075 bootbl
.data
->bootblock
.disktype
= ID_PFS_DISK
;
1076 fixederror("bootblock had wrong ID");
1077 if ((error
= volume
.writeblock((cachedblock_t
*)&bootbl
)))
1079 adderror("bootblock could not be written");
1092 /**************************************
1094 **************************************/
1096 /* Check plus fix deldir
1098 static error_t
RepairDeldir(void)
1104 bool rextdirty
= false, rootdirty
= false;
1106 volume
.showmsg("Checking deldir\n");
1108 /* check deldir version */
1109 if (rbl
->options
& MODE_DELDIR
)
1111 if (rbl
->options
& MODE_SUPERDELDIR
)
1113 ddsize
= rext
.data
->deldirsize
;
1114 volume
.status(0, "Deldir", ddsize
);
1116 for (i
=0; i
<32; i
++)
1118 if (rext
.data
->deldir
[i
])
1120 enterblock(rext
.data
->deldir
[i
]);
1123 sprintf(bericht
, "DELDIR %d\n", i
);
1124 volume
.showmsg(bericht
);
1131 if (dd_CheckBlock(rext
.data
->deldir
[i
], i
))
1133 if ((error
= ResBlockUsed(rext
.data
->deldir
[i
])))
1140 if (remove
&& mode
== repair
)
1142 sprintf(bericht
, "deldir block %d removed\n", i
);
1143 fixederror(bericht
);
1144 rext
.data
->deldir
[i
] = 0;
1145 ddsize
= min(ddsize
, i
+1);
1152 ddsize
= min(ddsize
, i
+1);
1156 if (ddsize
!= rext
.data
->deldirsize
)
1158 rext
.data
->deldirsize
= ddsize
;
1165 adderror("reference to old deldir");
1170 fixederror("reference to old deldir removed");
1179 adderror("deldir enabled, but missing");
1182 fixederror("deldir enabled, but missing");
1183 rbl
->options
&= ~MODE_DELDIR
;
1190 if (dd_CheckBlock(rbl
->deldir
, 0))
1192 if ((error
= ResBlockUsed(rbl
->deldir
)))
1198 if (remove
&& mode
== repair
)
1200 fixederror("deldir block removed\n");
1202 rbl
->options
&= ~MODE_DELDIR
;
1209 else /* deldir disabled */
1211 if (rext
.data
->deldirsize
)
1214 adderror("deldir size incorrect");
1217 fixederror("deldir size incorrect");
1218 rext
.data
->deldirsize
= 0;
1225 for (i
=0; i
<32; i
++)
1227 if (rext
.data
->deldir
[i
])
1229 fixederror("deldir block removed");
1230 rext
.data
->deldir
[i
] = 0;
1239 adderror("illegal deldir reference");
1242 fixederror("deldir block removed");
1250 c_WriteBlock((uint8
*)rbl
, ROOTBLOCK
+ volume
.firstblock
, volume
.blocksize
);
1252 volume
.writeblock((cachedblock_t
*)&rext
);
1258 static bool dd_CheckBlock(uint32 bloknr
, int seqnr
)
1261 c_deldirblock_t ddblk
;
1265 struct deldirentry
*dde
;
1268 volume
.progress(0, 1);
1271 ddblk
.data
= calloc(1, SIZEOF_RESBLOCK
);
1272 if ((error
= volume
.getblock((cachedblock_t
*)&ddblk
, bloknr
)))
1274 adderror("couldn't read deldirblock");
1280 if (ddblk
.data
->id
!= DELDIRID
)
1282 adderror("deldirblock error");
1287 if (ddblk
.data
->seqnr
!= seqnr
)
1289 adderror("deldirblock error");
1295 for (i
=0; i
<31; i
++)
1298 dde
= &ddblk
.data
->entries
[i
];
1303 if (ss
.stage
== syntax
)
1305 for (ddnr
= dde
->anodenr
; ddnr
; ddnr
= delnode
.next
)
1307 if (!GetAnode (&delnode
, ddnr
, false) || IsAnodeUsed(ddnr
))
1310 adderror("delfile anode error");
1313 fixederror("delfile anode error");
1315 volume
.writeblock((cachedblock_t
*)&ddblk
);
1320 blocks
+= (uint32
)(delnode
.clustersize
);
1323 size
= GetDDFileSize(dde
, &high
);
1324 if (!FileSizeCheck(size
, high
, blocks
))
1326 sprintf(bericht
, "delfile anode %#lx error", dde
->anodenr
);
1331 fixederror(bericht
);
1333 volume
.writeblock((cachedblock_t
*)&ddblk
);
1341 for (ddnr
= dde
->anodenr
; ddnr
; ddnr
= delnode
.next
)
1343 GetAnode(&delnode
, ddnr
, false);
1344 /* mark anodes as used */
1345 if (ss
.stage
<= anodebitmap
)
1348 /* for dde only the anodes need to be checked */
1349 // if (ss.stage == doubledel && isAnodeDouble(ddnr))
1350 // dde->anodenr = 0;
1359 /**************************************
1360 * Directory tree checker L2
1361 **************************************/
1365 struct dirstack
*parent
;
1371 #define pushdirstack(item) \
1372 (item)->parent = currentobject; \
1373 currentobject = (item)
1375 #define popdirstack() \
1376 currentobject = currentobject->parent
1378 struct dirstack
*currentobject
= NULL
;
1379 char objectname
[1024] = { 0 };
1380 char dirtype
[] = "DIR ";
1381 char filetype
[] = "FILE ";
1382 char hardlinktype
[] = "HARDLINK ";
1383 char softlinktype
[] = "SOFTLINK ";
1384 char rollovertype
[] = "ROLLOVER ";
1385 char unknowntype
[] = "OBJECT ";
1387 static void GetObjectName(void)
1389 struct dirstack
*n
, *ds
;
1390 char *b
= objectname
;
1396 while (ds
!= currentobject
)
1398 for (n
= currentobject
; n
->parent
!= ds
; n
=n
->parent
);
1399 if (n
->parent
&& n
->parent
->parent
)
1401 b
= stpcpy(b
, n
->name
);
1406 static void fixedfileerror(char *errortxt
)
1411 volume
.showmsg(currentobject
->objecttype
);
1412 volume
.showmsg(objectname
);
1413 volume
.showmsg("\n");
1418 fixederror(errortxt
);
1421 static void addfileerror(char *errortxt
)
1426 volume
.showmsg(currentobject
->objecttype
);
1427 volume
.showmsg(objectname
);
1428 volume
.showmsg("\n");
1433 /* Check directory tree. Track bitmap if needed.
1434 * Returns fatal error (0 = e_none. continue and errors fixed)
1436 static error_t
RepairDirTree(void)
1438 struct dirstack stackbottom
= {
1439 NULL
, "/", ANODE_ROOTDIR
, dirtype
};
1442 volume
.status(0, "root", 256);
1443 volume
.showmsg("Starting directory check\n");
1444 pushdirstack(&stackbottom
);
1445 error
= RepairDir(NULL
, NULL
);
1451 static error_t
RepairDir(struct direntry
*de
, c_dirblock_t
*parent
)
1453 uint32 mainanodenr
, anodenr
, parentanodenr
;
1455 error_t error
= e_none
;
1460 volume
.status(0, currentobject
->name
, 0);
1463 volume
.showmsg("DIR ");
1464 volume
.showmsg(currentobject
->name
);
1465 volume
.showmsg("\n");
1468 /* repair linkchain, remove if necessary */
1469 RepairLinkChain(de
, parent
);
1472 parentanodenr
= parent
? parent
->data
->anodenr
: 0;
1473 mainanodenr
= de
? de
->anode
: ANODE_ROOTDIR
;
1474 for (anodenr
= mainanodenr
; anodenr
; anodenr
=dirnode
.next
)
1477 if (!GetAnode(&dirnode
, anodenr
, true))
1481 if (dirnode
.clustersize
!= 1)
1483 fixedfileerror("directory anode has illegal clustersize");
1484 dirnode
.clustersize
= 1;
1485 SaveAnode(&dirnode
, anodenr
);
1488 enterblock(dirnode
.blocknr
);
1489 error
= RepairDirBlock(dirnode
.blocknr
, mainanodenr
, parentanodenr
);
1495 // BUG: an empty leading dirblock cannot be freed like
1496 // that, the anodes have to moved!
1498 // if (!dirnode.next)
1500 ResBlockUsed(dirnode
.blocknr
);
1506 // fixedfileerror("empty directory block");
1510 if (error
!= e_empty
)
1513 fixedfileerror("removing corrupt directory block");
1515 addfileerror("corrupt directory block");
1518 DeleteAnode(mainanodenr
, anodenr
);
1523 ResBlockUsed(dirnode
.blocknr
);
1529 KillReservedBitmap();
1532 if ((error
!= e_none
) || aborting
)
1539 static error_t
RepairDirBlock(uint32 bloknr
, uint32 anodenr
, uint32 parent
)
1541 c_dirblock_t dirblk
;
1542 struct direntry
*entry
;
1546 dirblk
.data
= calloc(1, SIZEOF_RESBLOCK
);
1547 if ((error
= volume
.getblock((cachedblock_t
*)&dirblk
, bloknr
)))
1553 /* check dirblock */
1554 if (dirblk
.data
->id
!= DBLKID
|| dirblk
.data
->anodenr
!= anodenr
||
1555 dirblk
.data
->parent
!= parent
)
1561 entry
= (struct direntry
*)dirblk
.data
->entries
;
1565 if ((error
= RepairDirEntry(entry
, &dirblk
)))
1570 fixedfileerror("removing corrupt directory entry");
1571 RemoveDirEntry(entry
, &dirblk
);
1575 addfileerror("corrupt directory entry");
1576 entry
= NEXTENTRY(entry
);
1580 entry
= NEXTENTRY(entry
);
1583 /* has to be done after main check, because an empty block can
1589 entry
= (struct direntry
*)dirblk
.data
->entries
;
1598 static error_t
RepairDirEntry(struct direntry
*de
, c_dirblock_t
*dirblk
)
1600 struct dirstack dirstack
;
1601 error_t error
= e_none
;
1603 volume
.progress(0, 1);
1604 if (!de
|| !de
->next
)
1607 if (ss
.stage
== syntax
)
1611 addfileerror("odd directory entry length");
1612 return e_direntry_error
;
1615 if (de
->nlength
+ offsetof(struct direntry
, nlength
) > de
->next
)
1617 addfileerror("invalid filename");
1618 return e_direntry_error
;
1621 if (de
->nlength
> volume
.fnsize
)
1623 addfileerror("filename too long");
1624 return e_direntry_error
;
1627 if (*FILENOTE(de
) + de
->nlength
+ offsetof(struct direntry
, nlength
) > de
->next
)
1629 addfileerror("invalid filenote");
1630 return e_direntry_error
;
1634 pushdirstack(&dirstack
);
1635 strncpy(dirstack
.name
, (char *)&de
->startofname
, de
->nlength
);
1636 dirstack
.name
[de
->nlength
] = 0;
1637 dirstack
.anodenr
= de
->anode
;
1638 dirstack
.objecttype
= unknowntype
;
1644 dirstack
.objecttype
= dirtype
;
1645 error
= RepairDir(de
, dirblk
);
1650 dirstack
.objecttype
= softlinktype
;
1651 error
= RepairSoftLink(de
, dirblk
);
1657 dirstack
.objecttype
= hardlinktype
;
1658 error
= RepairHardLink(de
, dirblk
);
1659 if (error
== e_remove
)
1663 case ST_ROLLOVERFILE
:
1665 dirstack
.objecttype
= rollovertype
;
1666 error
= RepairRollover(de
, dirblk
);
1671 dirstack
.objecttype
= filetype
;
1672 error
= RepairFile(de
, dirblk
);
1679 addfileerror("invalid filetype");
1680 error
= e_direntry_error
;
1688 static error_t
RepairFile(struct direntry
*de
, c_dirblock_t
*parent
)
1691 struct extrafields extra
;
1698 if ((error
= GetExtraFields(&extra
, de
)))
1701 /* check anode chain */
1702 if (ss
.stage
== syntax
)
1704 if (de
->type
!= ST_ROLLOVERFILE
&& (extra
.virtualsize
|| extra
.rollpointer
))
1706 extra
.virtualsize
= 0;
1707 extra
.rollpointer
= 0;
1708 SetExtraFields(&extra
, de
, parent
);
1709 fixedfileerror("dangling rollover");
1713 for (anodenr
= de
->anode
; anodenr
; anodenr
= filenode
.next
)
1715 if ((error
= CheckAnode(&filenode
, anodenr
, true)))
1718 blokken
+= filenode
.clustersize
;
1721 size
= GetDEFileSize(de
, &extra
, &high
);
1722 if (!FileSizeCheck(size
, high
, blokken
))
1724 addfileerror("invalid filesize");
1730 RepairLinkChain(de
, parent
);
1733 for (anodenr
= de
->anode
; anodenr
; anodenr
= filenode
.next
)
1735 GetAnode(&filenode
, anodenr
, true);
1736 if ((error
= AnodeUsed(anodenr
)))
1739 for (bl
= filenode
.blocknr
; bl
< filenode
.blocknr
+ filenode
.clustersize
; bl
++)
1740 if ((error
= MainBlockUsed(bl
)))
1744 if (error
!= e_none
)
1746 /* invalidate bitmaps to force generation in next stage. */
1747 InvalidBitmap(volume
.mainbitmap
);
1748 InvalidBitmap(volume
.anodebitmap
);
1755 /* Repair hardlink. If a hardlink is removed that has consequences for
1756 * the linkchain and the linked to file.
1758 static error_t
RepairHardLink(struct direntry
*de
, c_dirblock_t
*dirblok
)
1760 struct extrafields extra
;
1764 stats
.numhardlink
++;
1765 if ((error
= GetExtraFields(&extra
, de
)))
1770 addfileerror("invalid hardlink");
1775 if (!GetAnode (&linknode
, de
->anode
, true))
1778 /* check linknode linkdir (anode.blocknr) reference (objectdir is
1779 * checked by CheckLinkChain) */
1780 if (linknode
.blocknr
!= dirblok
->data
->anodenr
)
1782 addfileerror("invalid linknode directory reference");
1786 /* Check object reference
1787 * Find anodenr in objectdir, with problem of possible
1788 * corruption. Loose directories are not detected.
1789 * It is not checked if the link itself is infact a link,
1790 * just that it exists.
1792 switch (SearchInDir(linknode
.clustersize
, extra
.link
))
1795 addfileerror("dangling hardlink");
1799 case ST_ROLLOVERFILE
:
1802 if (de
->type
== ST_LINKDIR
)
1804 fixedfileerror("invalid hardlink");
1805 de
->type
= ST_LINKFILE
;
1806 volume
.writeblock((cachedblock_t
*)dirblok
);
1811 if (de
->type
== ST_LINKFILE
)
1813 fixedfileerror("invalid hardlink");
1814 de
->type
= ST_LINKDIR
;
1815 volume
.writeblock((cachedblock_t
*)dirblok
);
1820 if ((error
= AnodeUsed(de
->anode
)))
1827 static error_t
RepairSoftLink(struct direntry
*de
, c_dirblock_t
*dirblok
)
1829 stats
.numsoftlink
++;
1830 if (de
->fsize
> 108)
1831 return e_invalid_softlink
;
1833 return RepairFile(de
, dirblok
);
1836 static error_t
RepairRollover(struct direntry
*de
, c_dirblock_t
*dirblok
)
1838 struct extrafields extra
;
1841 stats
.numrollover
++;
1842 if ((error
= GetExtraFields(&extra
, de
)))
1845 if (extra
.virtualsize
> de
->fsize
||
1846 extra
.rollpointer
> de
->fsize
)
1848 fixedfileerror("invalid rollover fields");
1849 extra
.virtualsize
= 0;
1850 extra
.rollpointer
= 0;
1851 SetExtraFields(&extra
, de
, dirblok
);
1854 return RepairFile(de
, dirblok
);
1862 static error_t
RemoveDirEntry(struct direntry
*de
, c_dirblock_t
*dirblk
)
1864 uint8
*dest
, *source
;
1868 source
= dest
+ de
->next
;
1869 movelen
= ((uint8
*)(dirblk
->data
) + SIZEOF_RESBLOCK
) - dest
;
1870 if (movelen
> 0 && movelen
< SIZEOF_RESBLOCK
)
1872 memmove(dest
, source
, movelen
);
1873 volume
.writeblock((cachedblock_t
*)dirblk
);
1876 return e_fatal_error
;
1882 /* remove node from anodechain
1884 static error_t
DeleteAnode(uint32 anodechain
, uint32 node
)
1886 canode_t prev_node
, next_node
;
1890 if (anodechain
== node
)
1892 if (!GetAnode(&next_node
, node
, false))
1893 return e_anode_error
;
1895 if (!next_node
.next
|| !GetAnode(&next_node
, next_node
.next
, false))
1896 return e_anode_error
;
1898 SaveAnode(&next_node
, node
);
1903 previous
= anodechain
;
1906 if (!GetAnode(&prev_node
, previous
, false))
1907 return e_anode_error
;
1909 if (prev_node
.next
== node
)
1910 break; // we found it
1912 previous
= prev_node
.next
;
1915 GetAnode(&next_node
, prev_node
.next
, false);
1916 prev_node
.next
= next_node
.next
;
1917 SaveAnode(&prev_node
, prev_node
.nr
);
1923 /* Get the directory entry extension fields
1925 static error_t
GetExtraFields(struct extrafields
*extrafields
, struct direntry
*de
)
1927 uint16
*extra
= (uint16
*)extrafields
;
1928 uint16
*fields
= (uint16
*)(((uint8
*)de
)+de
->next
);
1931 // extract extrafields from directoryentry
1932 flags
= *(--fields
);
1933 for (i
=0; i
< sizeof(struct extrafields
)/2; i
++, flags
>>=1)
1934 *(extra
++) = (flags
&1) ? *(--fields
) : 0;
1936 // check flags field
1938 addfileerror("unknown extrafield flags found (ignored)");
1940 // patch protection lower 8 bits
1941 extrafields
->prot
|= de
->protection
;
1945 /* Set extrafields. Requirement is that the new directory entry fits.
1946 * To make sure it does, extrafields are removed only, not added.
1948 static error_t
SetExtraFields(struct extrafields
*extrafields
, struct direntry
*from
,
1949 c_dirblock_t
*dirblk
)
1951 uint8 entrybuffer
[MAX_ENTRYSIZE
];
1952 struct direntry
*to
;
1953 uint8
*dest
, *start
, *end
;
1957 to
= (struct direntry
*)entrybuffer
;
1958 memcpy(to
, from
, from
->next
);
1959 AddExtraFields(to
, extrafields
);
1961 /* make room for new direntry */
1962 diff
= to
->next
- from
->next
;
1963 dest
= (uint8
*)from
+ to
->next
;
1964 start
= (uint8
*)from
+ from
->next
;
1965 end
= (uint8
*)dirblk
->data
+ SIZEOF_RESBLOCK
;
1966 movelen
= (diff
> 0) ? (end
- dest
) : (end
- start
);
1967 memmove(dest
, start
, movelen
);
1969 /* add new direntry */
1970 memcpy((uint8
*)from
, to
, to
->next
);
1972 return volume
.writeblock((cachedblock_t
*)dirblk
);
1975 static void AddExtraFields(struct direntry
*direntry
, struct extrafields
*extra
)
1977 UWORD offset
, *dirext
;
1978 UWORD array
[16], i
= 0, j
= 0;
1979 UWORD flags
= 0, orvalue
;
1980 UWORD
*fields
= (UWORD
*)extra
;
1982 /* patch protection lower 8 bits */
1983 extra
->prot
&= 0xffffff00;
1984 offset
= (sizeof(struct direntry
) + (direntry
->nlength
) + *FILENOTE(direntry
)) & 0xfffe;
1985 dirext
= (UWORD
*)((UBYTE
*)(direntry
) + (UBYTE
)offset
);
1988 /* fill packed field array */
1989 for (i
= 0; i
< sizeof(struct extrafields
) / 2; i
++)
1993 array
[j
++] = *fields
++;
2004 /* add fields to direntry */
2007 *dirext
++ = array
[--i
];
2010 direntry
->next
= offset
+ 2 * j
+ 2;
2014 /* Repair the hardlinks chain referring to a file
2016 static error_t
RepairLinkChain(struct direntry
*de
, c_dirblock_t
*dirblk
)
2018 struct extrafields extra
;
2023 /* check extra fields */
2024 if ((error
= GetExtraFields(&extra
, de
)))
2027 /* check if object has a linkchain */
2031 if (!GetAnode(&linknode
, extra
.link
, false))
2032 return e_anode_error
;
2034 parent
= dirblk
->data
->anodenr
;
2037 // check objectdir (clustersize) against actual objectdir
2038 if (linknode
.clustersize
!= parent
)
2040 fixedfileerror("invalid hardlink");
2041 linknode
.clustersize
= parent
;
2042 SaveAnode(&linknode
, linknode
.nr
);
2045 // check linkdir left to HardLink::Check
2046 if (!SearchInDir(linknode
.blocknr
, linknode
.nr
))
2048 fixedfileerror("dangling hardlink");
2049 if ((error
= DeleteAnode(extra
.link
, linknode
.nr
))
2050 && (linknode
.nr
== extra
.link
))
2053 SetExtraFields(&extra
, de
, dirblk
);
2060 if (!GetAnode (&linknode
, linknode
.next
, false))
2061 return e_anode_error
;
2065 /* Get & check an anode
2067 static error_t
CheckAnode(canode_t
*anode
, uint32 nr
, bool fix
)
2069 /* if an anodeblock does not exist, it is considered empty */
2070 if (!GetAnode(anode
, nr
, fix
))
2073 if (anode
->clustersize
== 0 && anode
->blocknr
== 0 && anode
->next
== 0)
2079 /* Search file by anodenr in a directory
2080 * return filetype or 0 for not found
2082 int SearchInDir(uint32 diranodenr
, uint32 target
)
2085 c_dirblock_t dirblk
;
2086 struct direntry
*de
;
2087 error_t error
= e_none
;
2090 /* Get directory and find object */
2091 dirblk
.data
= calloc(1, SIZEOF_RESBLOCK
);
2092 while (error
== e_none
&& diranodenr
)
2094 if (!GetAnode(&anode
, diranodenr
, false))
2097 if ((error
= volume
.getblock((cachedblock_t
*)&dirblk
, anode
.blocknr
)) || aborting
)
2100 de
= FIRSTENTRY(&dirblk
);
2103 if (de
->anode
== target
)
2113 diranodenr
= anode
.next
;
2120 /**************************************
2121 * Anode tree checker L2
2122 **************************************/
2124 /* Check anode tree.
2125 * Returns fatal errors (e_none = continue)
2127 static error_t
RepairAnodeTree(void)
2131 uint32 child_blk_nr
;
2133 volume
.showmsg("Checking anodetree\n");
2134 if (rbl
->options
& MODE_SUPERINDEX
)
2136 volume
.status(0, "Anodetree", 100);
2138 for (i
=0; i
<MAXSUPER
+1; i
++)
2140 if ((child_blk_nr
= rext
.data
->superindex
[i
]))
2142 if ((error
= RepairSuperIndex(&rext
.data
->superindex
[i
], i
)) || aborting
)
2145 if (rext
.data
->superindex
[i
] != child_blk_nr
)
2146 volume
.writeblock((cachedblock_t
*)&rext
);
2152 volume
.status(0, "Anodetree", 100);
2154 for (i
=0; i
<MAXSMALLINDEXNR
+1; i
++)
2156 if ((child_blk_nr
= rbl
->idx
.small
.indexblocks
[i
]))
2158 if ((error
= RepairAnodeIndex(&rbl
->idx
.small
.indexblocks
[i
], i
)) || aborting
)
2161 if (rbl
->idx
.small
.indexblocks
[i
] != child_blk_nr
)
2162 c_WriteBlock((uint8
*)rbl
, ROOTBLOCK
+ volume
.firstblock
, volume
.blocksize
);
2170 error_t
RepairSuperIndex(uint32
*bloknr
, uint32 seqnr
)
2172 return RepairIndexBlock(SBLKID
, RepairAnodeIndex
, bloknr
, seqnr
);
2175 error_t
RepairAnodeIndex(uint32
*bloknr
, uint32 seqnr
)
2177 volume
.progress(0, 0); // reset progress bar
2178 return RepairIndexBlock(IBLKID
, RepairAnodeBlock
, bloknr
, seqnr
);
2181 /* missing: check of first, reserved anodes.
2182 * if blocknr is 0 --> search and build
2184 error_t
RepairAnodeBlock(uint32
*bloknr
, uint32 seqnr
)
2186 error_t error
= e_none
;
2187 c_anodeblock_t ablk
;
2191 ablk
.data
= calloc(1, SIZEOF_RESBLOCK
);
2194 if ((error
= volume
.getblock((cachedblock_t
*)&ablk
, *bloknr
)))
2200 enterblock(*bloknr
);
2203 // check syntax block
2204 if (ss
.stage
== syntax
)
2206 if (ablk
.data
->id
!= ABLKID
|| ablk
.data
->seqnr
!= seqnr
)
2210 sprintf(bericht
, "anodeblock seqnr %lu blocknr %lu has an incorrect id", seqnr
, *bloknr
);
2216 volume
.status(1, "Searching anode block", 256);
2217 oldbloknr
= *bloknr
;
2218 if ((*bloknr
= SearchBlock(ABLKID
, seqnr
, oldbloknr
, 0, 0, 0)))
2220 sprintf(bericht
, "replaced block %lu with backup %lu", oldbloknr
, *bloknr
);
2221 fixederror(bericht
);
2225 /* remove corrupt block */
2226 fixederror("no replacement found - removing block");
2235 ResBlockUsed(*bloknr
);
2241 /**************************************
2242 * Bitmap tree checker L2
2243 **************************************/
2245 /* Check bitmap tree.
2246 * Returns fatal errors (e_none = continue)
2248 static error_t
RepairBitmapTree(void)
2250 error_t error
= e_none
;
2254 volume
.status(0, "Bitmap", 100);
2255 volume
.showmsg("Checking bitmap\n");
2257 num
= ((volume
.lastblock
- volume
.firstblock
- rbl
->lastreserved
- 1) + 31) / 32;
2258 num
= (num
+ INDEX_PER_BLOCK
*INDEX_PER_BLOCK
- 1)/(INDEX_PER_BLOCK
* INDEX_PER_BLOCK
);
2259 for (i
=0; i
< ((rbl
->options
& MODE_SUPERINDEX
) ? (MAXBITMAPINDEX
+ 1) : (MAXSMALLBITMAPINDEX
+ 1)); i
++)
2261 blknr
= rbl
->idx
.large
.bitmapindex
[i
];
2264 /* force bitmapindexblock to be searched and created */
2266 rbl
->idx
.large
.bitmapindex
[i
] = rbl
->lastreserved
;
2268 if ((error
= RepairBitmapIndex(&rbl
->idx
.large
.bitmapindex
[i
], i
)) || aborting
)
2271 if (rbl
->idx
.large
.bitmapindex
[i
] != blknr
)
2272 c_WriteBlock((uint8
*)rbl
, ROOTBLOCK
+ volume
.firstblock
, volume
.blocksize
);
2280 /* change blocknr if necessary
2282 error_t
RepairBitmapIndex(uint32
*bloknr
, uint32 seqnr
)
2284 volume
.progress(0, 0); // reset progress bar
2285 return RepairIndexBlock(BMIBLKID
, RepairBitmapBlock
, bloknr
, seqnr
);
2288 error_t
RepairBitmapBlock(uint32
*bloknr
, uint32 seqnr
)
2290 error_t error
= e_none
;
2291 c_bitmapblock_t bmblk
;
2295 bmblk
.data
= calloc(1, SIZEOF_RESBLOCK
);
2296 if (GetBuildBlock(BMBLKID
, seqnr
))
2301 if ((error
= volume
.getblock((cachedblock_t
*)&bmblk
, *bloknr
)))
2308 enterblock(*bloknr
);
2310 // check syntax block
2311 if (ss
.stage
== syntax
)
2313 if (bmblk
.data
->id
!= BMBLKID
|| bmblk
.data
->seqnr
!= seqnr
)
2317 sprintf(bericht
, "bitmapblock seqnr %lu blocknr %lu has an incorrect id", seqnr
, *bloknr
);
2323 volume
.status(1, "Searching bitmap block", 256);
2324 oldbloknr
= *bloknr
;
2325 if ((*bloknr
= SearchBlock(BMBLKID
, seqnr
, oldbloknr
, 0, 0, 0)))
2327 sprintf(bericht
, "replaced block %lu with backup %lu", oldbloknr
, *bloknr
);
2328 fixederror(bericht
);
2332 volume
.showmsg("No replacement block found\n");
2334 error
= BuildBitmapBlock(&bmblk
, seqnr
);
2337 adderror("building new bitmapblock failed");
2339 fixederror("new bitmapblock created");
2346 ResBlockUsed(*bloknr
);
2352 /**************************************
2353 * Check index blocks.
2354 * Returns fatal errors (e_none = continue)
2356 error_t
RepairIndexBlock(uint16 bloktype
, error_t (*repairchild
)(uint32
*, uint32
),
2357 uint32
*bloknr
, uint32 seqnr
)
2359 error_t error
= e_none
;
2360 c_indexblock_t iblk
= { 0 };
2361 cachedblock_t
*cblk
;
2363 uint32 child_blk_nr
, oldbloknr
;
2365 enterblock(*bloknr
);
2367 if ((cblk
= GetBuildBlock(bloktype
, seqnr
)))
2368 iblk
= *(c_indexblock_t
*)cblk
;
2372 iblk
.data
= calloc(1, SIZEOF_RESBLOCK
);
2374 /* read or build indexblock
2376 if ((error
= volume
.getblock((cachedblock_t
*)&iblk
, *bloknr
)))
2383 if (ss
.stage
== syntax
)
2385 if (iblk
.data
->id
!= bloktype
|| iblk
.data
->seqnr
!= seqnr
)
2390 "indexblock %lu blocknr %lu type %x has incorrect id of %x, %lu",
2391 seqnr
, *bloknr
, bloktype
, iblk
.data
->id
, iblk
.data
->seqnr
);
2397 volume
.status(1, "Searching index block", 256);
2398 oldbloknr
= *bloknr
;
2399 if ((*bloknr
= SearchBlock(bloktype
, seqnr
, oldbloknr
, 0, 0, 0)))
2401 sprintf(bericht
, "replaced block %lu with backup %lu", oldbloknr
, *bloknr
);
2402 fixederror(bericht
);
2404 return RepairIndexBlock(bloktype
, repairchild
, bloknr
, seqnr
);
2408 volume
.showmsg("No replacement block found\n");
2410 if ((error
= BuildIndexBlock(&iblk
, bloktype
, seqnr
)))
2412 adderror("building new indexblock failed");
2416 fixederror("new indexblock created");
2421 /* check mode failure */
2422 ResBlockUsed(*bloknr
);
2430 for (i
=0; i
<LONGS_PER_BMB
; i
++)
2432 if ((child_blk_nr
= iblk
.data
->index
[i
]))
2434 volume
.progress(0, 1);
2435 switch (repairchild((uint32
*)&iblk
.data
->index
[i
], seqnr
*LONGS_PER_BMB
+ i
))
2442 iblk
.data
->index
[i
] = 0;
2450 if (child_blk_nr
!= iblk
.data
->index
[i
] && iblk
.mode
== check
)
2451 volume
.writeblock((cachedblock_t
*)&iblk
);
2456 if (iblk
.mode
== check
)
2458 /* not necessary (allowed) for generated blocks */
2459 ResBlockUsed(*bloknr
);
2466 /**************************************
2467 * Bitmap Generator L3
2468 **************************************/
2476 static error_t
InitReservedBitmap(void)
2478 uint32 reservedsize
, bloknr
, cluster
;
2480 KillReservedBitmap();
2481 if (rbl
->firstreserved
!= 2)
2483 fixederror("illegal firstreserved");
2484 rbl
->firstreserved
= 2;
2487 // reservedsize cannot be smaller then 0 and is not allowed to take more than
2488 // 1/8th of the partition.
2489 volume
.lastreserved
= rbl
->lastreserved
;
2490 reservedsize
= rbl
->lastreserved
/volume
.rescluster
- rbl
->firstreserved
+ 1;
2492 if (reservedsize
<=0 || reservedsize
> volume
.disksize
/8)
2494 sprintf(bericht
, "illegal reserved area size of %lu blocks", reservedsize
);
2497 if (!(bloknr
= SearchLastReserved(&volume
)))
2498 return e_fatal_error
;
2501 rbl
->lastreserved
= volume
.lastreserved
= bloknr
;
2504 if ((rext
.data
->reserved_roving
+ 31)/32 > reservedsize
)
2506 rext
.data
->reserved_roving
= 0;
2507 volume
.writeblock((cachedblock_t
*)&rext
);
2510 cluster
= 1 + ((reservedsize
> 125*32) ? (reservedsize
- 125*32 + 256*32 - 1)/(256*32) : 0);
2511 // cluster is rounded up to closest reserved blocksize
2512 cluster
= (((cluster
+ rbl
->reserved_blksize
/ 1024 - 1) & ~(rbl
->reserved_blksize
/ 1024 - 1)) * 1024)>>volume
.blockshift
;
2513 if (rbl
->rblkcluster
!= cluster
)
2515 rbl
->rblkcluster
= cluster
;
2517 fixederror("wrong rootblock cluster size");
2520 volume
.resbitmap
= bg_InitBitmap(rbl
->firstreserved
, rbl
->lastreserved
, volume
.rescluster
);
2521 if (!volume
.resbitmap
)
2522 return e_fatal_error
;
2524 /* mark rootblock cluster as used */
2525 for (bloknr
= 2; bloknr
< 2+cluster
; bloknr
+= volume
.rescluster
)
2526 ResBlockUsed(bloknr
);
2531 /* assumes valid anodetree syntax
2533 static error_t
InitAnodeBitmap(void)
2535 c_indexblock_t iblk
;
2540 iblk
.data
= calloc(1, SIZEOF_RESBLOCK
);
2542 /* determine number of anodebitmap blocks
2543 * If any anode or indexblocks are generated, the anodebitmap has to be
2544 * destroyed and regenerated.
2546 if (rbl
->options
& MODE_SUPERINDEX
)
2548 for (s
=MAXSUPER
; !rext
.data
->superindex
[s
] && s
; s
--);
2550 if ((error
= GetResBlock((cachedblock_t
*)&iblk
, SBLKID
, s
, false)))
2556 for (i
=INDEX_PER_BLOCK
- 1; !iblk
.data
->index
[i
]; i
--);
2560 for (s
=0, i
=MAXSMALLINDEXNR
; !rbl
->idx
.small
.indexblocks
[i
] && i
; i
--);
2563 s
= s
*INDEX_PER_BLOCK
*INDEX_PER_BLOCK
*ANODES_PER_BLOCK
;
2564 s
+= (++i
* INDEX_PER_BLOCK
* ANODES_PER_BLOCK
) - 1;
2565 volume
.anodebitmap
= bg_InitBitmap(0, s
, 1);
2566 for (i
=0; i
<ANODE_ROOTDIR
; i
++)
2573 /* Initialise generation of main bitmap
2575 static error_t
InitMainBitmap(void)
2578 volume
.mainbitmap
= bg_InitBitmap(rbl
->lastreserved
+1,
2579 volume
.lastblock
-volume
.firstblock
, 1);
2581 if (!volume
.mainbitmap
)
2582 return e_fatal_error
;
2587 void KillAnodeBitmap(void)
2589 bg_KillBitmap(&volume
.anodebitmap
);
2592 void KillMainBitmap(void)
2594 bg_KillBitmap(&volume
.mainbitmap
);
2597 void KillReservedBitmap(void)
2599 bg_KillBitmap(&volume
.resbitmap
);
2602 /* Compare generated reserved bitmap with the actual bitmap
2603 * and fix differences.
2605 * - syntax disk is correct
2607 * - reserved bitmap generated AND valid
2609 static error_t
RepairReservedBitmap(void)
2612 bitmapblock_t
*bitmap
;
2613 uint32 i
, j
, mask
, blknr
, blocksfree
= 0;
2616 uint32 nuba
=0, ubna
=0;
2619 volume
.status(0, "validating reserved", volume
.resbitmap
->lwsize
/0xff);
2621 /* first save current rootblock */
2622 if ((error
= c_WriteBlock ((uint8
*)rbl
, ROOTBLOCK
+ volume
.firstblock
, volume
.blocksize
)))
2625 /* now get reserved bitmap with rootblock in memory */
2626 if (!(lrb
= (rootblock_t
*)AllocBufMem(volume
.blocksize
* rbl
->rblkcluster
)))
2627 return e_out_of_memory
;
2630 for (i
=0; i
<rbl
->rblkcluster
; i
++)
2632 if ((error
= c_GetBlock (t
, ROOTBLOCK
+ volume
.firstblock
+ i
, volume
.blocksize
)))
2634 adderror("reserved bitmap could not be loaded");
2638 t
+= volume
.blocksize
;
2641 bitmap
= (bitmapblock_t
*)(lrb
+ 1);
2642 if (bitmap
->id
!= BMBLKID
)
2644 /* this is also done at BUILD ROOTBLOCK */
2646 adderror("reserved bitmap id is wrong");
2648 fixederror("reserved bitmap id was wrong");
2650 memset(bitmap
, 0, rbl
->rblkcluster
*volume
.blocksize
- sizeof(*lrb
));
2651 bitmap
->id
= BMBLKID
;
2654 /* now we can check */
2655 for (i
=0; i
<volume
.resbitmap
->lwsize
; i
++)
2661 volume
.progress(0, 1);
2664 for (j
=0; j
<32; j
++)
2666 mask
= 0x80000000 >> j
;
2667 blknr
= (i
*32 + j
)*volume
.resbitmap
->step
+ volume
.resbitmap
->start
;
2669 if (blknr
<= volume
.resbitmap
->stop
)
2671 if ((volume
.resbitmap
->map
[i
] & mask
) !=
2672 (bitmap
->bitmap
[i
] & mask
))
2674 if (volume
.resbitmap
->map
[i
] & mask
)
2677 sprintf(bericht
, "reserved block %lu not used but allocated", blknr
);
2679 fixederror(bericht
);
2680 lrb
->reserved_free
++;
2685 sprintf(bericht
, "reserved block %lu used but not allocated", blknr
);
2687 fixederror(bericht
);
2688 lrb
->reserved_free
--;
2691 bitmap
->bitmap
[i
] ^= mask
;
2695 if (bitmap
->bitmap
[i
] & mask
)
2703 sprintf(bericht
, "%lu reserved blocks not used but allocated", nuba
);
2705 fixederror(bericht
);
2710 sprintf(bericht
, "%lu reserved blocks used but not allocated", ubna
);
2712 fixederror(bericht
);
2715 // check blocks free
2716 if (lrb
->reserved_free
!= blocksfree
&& !aborting
)
2719 fixederror("wrong number of reserved blocks free");
2720 lrb
->reserved_free
= blocksfree
;
2725 if (dirty
&& !aborting
)
2728 for (i
=0; i
<lrb
->rblkcluster
; i
++)
2730 error
= c_WriteBlock (t
, ROOTBLOCK
+ volume
.firstblock
+ i
, volume
.blocksize
);
2731 t
+= volume
.blocksize
;
2733 memcpy(rbl
, lrb
, SIZEOF_RESBLOCK
);
2740 /* Compare generated bitmap with actual bitmap and fix found
2741 * differences. Pre conditions:
2742 * - syntax disk correct
2743 * - main bitmap generated and VALID
2744 * - rootblock and rext loaded
2746 static error_t
RepairMainBitmap(void)
2748 uint32 k
=0, i
, j
, bmseqnr
;
2749 uint32 mask
, blknr
, blocksfree
= 0;
2750 c_bitmapblock_t bmb
;
2752 error_t error
= e_none
;
2755 uint32 nuba
=0, ubna
=0;
2758 volume
.showmsg("checking main bitmap\n");
2760 gbm
= volume
.mainbitmap
;
2761 bmb
.data
= calloc(1, SIZEOF_RESBLOCK
);
2762 volume
.status(0, "validating main", gbm
->lwsize
/INDEX_PER_BLOCK
);
2764 for (bmseqnr
= 0; bmseqnr
<= gbm
->lwsize
/INDEX_PER_BLOCK
; bmseqnr
++)
2766 volume
.progress(0, 1);
2768 if ((error
= GetResBlock((cachedblock_t
*)&bmb
, BMBLKID
, bmseqnr
, true)) || aborting
)
2771 if ((error
= BuildBitmapBlock(&bmb
, bmseqnr
)))
2777 for (i
=0; i
<INDEX_PER_BLOCK
; i
++, k
++)
2779 for (j
=0; j
<32; j
++)
2781 mask
= 0x80000000 >> j
;
2782 blknr
= k
*32 + j
+ gbm
->start
;
2784 if (blknr
<= gbm
->stop
)
2786 if ((bmb
.data
->bitmap
[i
] & mask
) !=
2787 (gbm
->map
[k
] & mask
))
2789 if (gbm
->map
[k
] & mask
)
2792 // sprintf(bericht, "block %d not used but allocated", blknr);
2794 // fixederror(bericht);
2800 // sprintf(bericht, "block %d used but not allocated", blknr);
2802 // fixederror(bericht);
2806 bmb
.data
->bitmap
[i
] ^= mask
;
2808 if ((error
= volume
.writeblock ((cachedblock_t
*)&bmb
)))
2815 if (bmb
.data
->bitmap
[i
] & mask
)
2824 sprintf(bericht
, "%lu data blocks not used but allocated", nuba
);
2825 fixederror(bericht
);
2830 sprintf(bericht
, "%lu data blocks used but not allocated", ubna
);
2831 fixederror(bericht
);
2834 // check blocks free
2835 if (rbl
->blocksfree
!= blocksfree
)
2837 fixederror("wrong number of blocks free");
2838 rbl
->blocksfree
= blocksfree
;
2843 error
= c_WriteBlock ((uint8
*)rbl
, ROOTBLOCK
+ volume
.firstblock
, volume
.blocksize
);
2850 /* Compare anodes with generated anode bitmap. Fix found
2851 * differences. Pre conditions:
2852 * - syntax disk correct
2853 * - anode bitmap generated and VALID
2854 * - rootblock and rext loaded
2856 static error_t
RepairAnodeBitmap(void)
2861 bitmap_t
*gbm
= volume
.anodebitmap
;
2863 uint32 nuba
=0, ubna
=0;
2866 volume
.showmsg("checking anode bitmap\n");
2867 volume
.status(0, "validating anodes", (gbm
->stop
- gbm
->start
)/32);
2869 for (i
=gbm
->start
; i
<=gbm
->stop
; i
++)
2875 volume
.progress(0,1);
2878 anodeused
= !(gbm
->map
[i
/32] & (0x80000000UL
>> i
%32));
2879 anodenr
= (i
/ANODES_PER_BLOCK
<< 16) + i
%ANODES_PER_BLOCK
;
2881 error
= CheckAnode(&anode
, anodenr
, false);
2883 if ((error
== e_empty
) == anodeused
)
2889 sprintf(bericht
, "anode %#lx used but not allocated", anodenr
);
2890 fixederror(bericht
);
2896 anode
.clustersize
= 0;
2897 anode
.blocknr
= 0xffffffff;
2899 SaveAnode(&anode
, anodenr
);
2906 sprintf(bericht
, "anode %#lx not used but allocated", anodenr
);
2907 fixederror(bericht
);
2916 SaveAnode(&anode
, anodenr
);
2924 sprintf(bericht
, "%lu anodes not used but allocated", nuba
);
2925 fixederror(bericht
);
2930 sprintf(bericht
, "%lu anodes used but not allocated", ubna
);
2931 fixederror(bericht
);
2937 error_t
ResBlockUsed(uint32 bloknr
)
2939 error_t error
= e_none
;
2941 if (ss
.stage
<= resbitmap
)
2943 error
= bg_ItemUsed(volume
.resbitmap
, bloknr
);
2944 if (error
== e_double_allocation
)
2946 sprintf(bericht
, "reserved block %lu is double allocated", bloknr
);
2953 static error_t
MainBlockUsed(uint32 bloknr
)
2955 error_t error
= e_none
;
2957 if (ss
.stage
<= mainbitmap
)
2959 error
= bg_ItemUsed(volume
.mainbitmap
, bloknr
);
2960 if (error
== e_double_allocation
)
2962 sprintf(bericht
, "block %lu is double allocated", bloknr
);
2963 addfileerror(bericht
);
2969 static error_t
AnodeUsed(uint32 nr
)
2971 error_t error
= e_none
;
2973 if (ss
.stage
<= anodebitmap
)
2975 nr
= (nr
>> 16) * ANODES_PER_BLOCK
+ (uint16
)nr
;
2976 error
= bg_ItemUsed(volume
.anodebitmap
, nr
);
2977 if (error
== e_double_allocation
)
2979 sprintf(bericht
, "anode %#lx is double allocated", nr
);
2980 addfileerror(bericht
);
2986 static BOOL
IsAnodeUsed(uint32 nr
)
2988 if (!nr
) return FALSE
;
2989 nr
= (nr
>> 16) * ANODES_PER_BLOCK
+ (uint16
)nr
;
2990 return bg_IsItemUsed(volume
.anodebitmap
, nr
);
2993 /* private functions
2996 /* initialise a bitmap for generation. The range is start to stop with
2999 static bitmap_t
*bg_InitBitmap(int32 start
, int32 stop
, int32 step
)
3003 if (!(mybitmap
= calloc(1, sizeof(bitmap_t
))))
3006 mybitmap
->start
= start
;
3007 mybitmap
->stop
= stop
;
3008 mybitmap
->step
= step
;
3009 mybitmap
->lwsize
= (((stop
-start
+step
)/step
)+31)/32;
3011 if (!(mybitmap
->map
= malloc(4 * mybitmap
->lwsize
)))
3014 volume
.showmsg("DOCTOR ERROR: out of memory\n");
3018 memset(mybitmap
->map
, 0xff, mybitmap
->lwsize
*4);
3019 mybitmap
->valid
= true;
3023 static void bg_KillBitmap(bitmap_t
**bm
)
3035 static error_t
bg_ItemUsed(bitmap_t
*bm
, uint32 nr
)
3042 if (nr
< bm
->start
|| nr
> bm
->stop
)
3043 return e_outside_bitmap_error
;
3051 if (bm
->map
[index
] & (0x80000000UL
>> bit
))
3053 bm
->map
[index
] ^= (0x80000000UL
>> bit
);
3058 return e_double_allocation
;
3062 static BOOL
bg_IsItemUsed(bitmap_t
*bm
, uint32 nr
)
3071 if (bm
->map
[index
] & (0x80000000UL
>> bit
))