Added pfsdoctor. Includes PFS3 v19 large partition and file size support.
[AROS.git] / rom / filesys / pfs3 / pfsdoctor / standardscan.c
blob3847d1357f78645fb930be409b05c16a4f02284c
1 /* $Id$
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
7 * Bugfixes etc (1.4)
9 * Revision 2.8 1999/08/01 10:48:21 Michiel
10 * less verbose
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
15 * Reduced cachesize
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
21 * fixed logfile bug
22 * made verbose less verbose
24 * Revision 2.4 1999/05/07 16:49:00 Michiel
25 * bugfixes etc
27 * Revision 2.3 1999/05/04 17:59:09 Michiel
28 * check mode, logfile, search rootblock implemented
29 * bugfixes
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
35 * compiled
37 * Revision 1.1 1999/04/19 22:16:53 Michiel
38 * Initial revision
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>
48 #include <string.h>
49 #include <stdio.h>
50 #include <math.h>
51 #include <stddef.h>
52 #include <stdlib.h>
53 #include <proto/asl.h>
54 #include <proto/exec.h>
55 #include "pfs3.h"
56 #include "doctor.h"
58 long __stack = 30*1024;
59 extern struct Window *CheckRepairWnd;
61 /**************************************
62 * Globals
63 **************************************/
65 struct
67 /* state flags */
68 uint32 flags; /* internal flags */
69 uint32 opties; /* options */
70 int pass;
71 BOOL verbose;
72 BOOL unformat;
74 enum {syntax, resbitmap, mainbitmap, anodebitmap, finished} stage;
76 struct MinList *doubles;
77 } ss;
79 volume_t volume;
80 char bericht[256];
81 rootblock_t *rbl= NULL;
82 c_extensionblock_t rext = { 0 };
83 bool redosyntax;
84 bool aborting = 0; // used by break trap
86 /**************************************
87 * Protos
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 /**************************************
136 * Break function L1
137 **************************************/
139 #ifdef __SASC
140 int brk(void)
142 aborting = 1;
143 return 0;
146 void __regargs __chkabort(void)
148 /* Check & clear CTRL_C signal */
149 if(SetSignal(0L,SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C)
151 brk();
154 #endif
156 static BOOL FileSizeCheck(ULONG low, ULONG high, ULONG numblocks)
158 ULONG size, oldlow;
160 oldlow = low;
161 low += volume.blocksize - 1;
162 if (low < oldlow)
163 high++;
164 size = low >> volume.blockshift;
165 size |= high << (32 - volume.blockshift);
166 if (size == numblocks)
167 return TRUE;
168 return FALSE;
171 /**************************************
172 * StandardScan L1
173 **************************************/
175 // public interface
176 error_t StandardScan(uint32 opties)
178 uint32 flags;
180 aborting = 0;
181 // onbreak(&brk);
182 memset(&ss, sizeof(ss), 0);
183 opties = opties;
185 flags = opties;
186 if (opties & (SSF_CHECK|SSF_FIX))
187 flags |= SSF_GEN_BMMASK;
189 /* init stats */
190 memset(&stats, 0, sizeof(stats));
191 return mainStandardScan(flags);
194 // core standardscan
195 static error_t mainStandardScan(uint32 flags)
197 error_t error;
199 volume.showmsg("Initializing\n");
200 ss.flags = flags;
201 ss.stage = syntax;
202 ss.pass = stats.pass = 1;
203 ss.verbose = flags & SSF_VERBOSE;
204 ss.unformat = flags & SSF_UNFORMAT;
206 InitFullScan();
208 /* unformat .. */
209 if (ss.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);
222 /* read rootblock */
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);
237 rext.mode = check;
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");
246 /* stage 1 */
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)
255 break;
256 error = ss_CheckDirTree();
257 if ((error != e_none) || aborting)
258 return exitStandardScan(error);
259 if (mode == check)
260 break;
261 ss.pass++;
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);
271 return e_none;
274 static error_t exitStandardScan(error_t error)
276 UpdateCache();
278 if (rbl)
280 FreeBufMem(rbl);
281 rbl = NULL;
284 if (rext.mode == check)
285 free (rext.data);
286 rext.data = NULL;
288 KillReservedBitmap();
289 KillAnodeBitmap();
290 KillMainBitmap();
291 ExitFullScan();
293 if ((error != e_none) || aborting)
294 volume.showmsg("ABORTED\n");
295 else if (ss.unformat)
297 volume.askuser(
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);
303 return error;
307 /* main loop: check the partition defined by the rootblock and
308 * rext (rootblock extension)
310 static error_t ss_CheckDirTree(void)
312 error_t error;
313 int newpassneeded = 0;
315 clearstats();
316 redosyntax = false;
317 switch (ss.stage)
319 case syntax:
320 case resbitmap:
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)))
328 return error;
330 /* anode blok tree */
331 /* if anodeindexblok faulty --> create (using DiskScan) */
332 if ((error = RepairAnodeTree()) || aborting)
333 return error;
335 /* bitmap */
336 /* check syntax bitmap tree
337 * if block faulty --> create, kill bitmap, ss_makebm = false
338 * and continue */
339 if ((error = RepairBitmapTree()) || aborting)
340 return error;
342 case mainbitmap:
344 if (ss.flags & SSF_GEN_MAINBITMAP)
345 InitMainBitmap();
347 case anodebitmap:
349 if (ss.flags & SSF_GEN_ANODEBITMAP)
350 InitAnodeBitmap();
352 default:
354 break;
357 /* deldir */
358 if ((error = RepairDeldir()) || aborting)
359 return error;
361 /* directory tree */
362 if ((error = RepairDirTree()) || aborting)
363 return error;
365 /* on hardlink conflict */
366 if (redosyntax)
368 ss.stage = syntax;
369 return e_none;
372 switch (ss.stage)
374 case syntax:
375 case resbitmap:
377 /* need another pass if blocks were created
378 * (should not be necessary!!)
380 if (!IsMinListEmpty(&volume.buildblocks))
381 newpassneeded = 1;
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()))
390 return error;
392 if ((error = RepairReservedBitmap()) || aborting)
393 return error;
395 else
397 if (ss.stage < resbitmap)
399 ss.stage = resbitmap;
400 break;
402 else
403 return e_res_bitmap_fail; /* fatal error */
406 if (newpassneeded)
407 break;
409 case mainbitmap:
410 case anodebitmap:
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;
420 break;
422 else
423 return e_main_bitmap_fail; /* fatal error */
426 if (!IsBitmapValid(volume.anodebitmap))
428 if (ss.stage < anodebitmap)
430 ss.stage = anodebitmap;
431 break;
433 else
434 return e_anode_bitmap_fail;
437 if ((error = RepairMainBitmap()) || aborting)
438 return error;
440 if ((error = RepairAnodeBitmap()) || aborting)
441 return error;
443 ss.stage = finished;
444 break;
446 default:
447 // case doubledel:
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;
460 return e_none;
464 /**************************************
465 * Volume functions
466 **************************************/
468 /* functions for in cache struct
469 * gets block from reserved area and checks partition
470 * borders etc.
471 * status/errors:
472 * read/write errors
473 * e_none
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;
494 return e_none;
498 error_t vol_GetBlock(cachedblock_t *blok, ULONG bloknr)
500 error_t error;
501 ULONG realbloknr;
503 realbloknr = bloknr;
504 if ((error = vol_CheckBlockNr(&realbloknr)))
505 return error;
507 if ((error = c_GetBlock((uint8 *)blok->data, realbloknr, SIZEOF_RESBLOCK)))
509 return error;
511 else
513 blok->mode = check;
514 blok->blocknr = bloknr;
515 return e_none;
519 error_t vol_WriteBlock(cachedblock_t *blok)
521 int status;
522 uint32 bloknr;
524 if (blok->mode != build)
526 bloknr = blok->blocknr;
527 if ((status = vol_CheckBlockNr(&bloknr)))
528 return status;
530 return c_WriteBlock((uint8 *)blok->data, bloknr, SIZEOF_RESBLOCK);
533 return e_none;
537 /**************************************
538 * GetRootBlock
539 **************************************/
541 // public functions
543 static error_t BuildRootBlock_hub(void)
545 error_t error;
547 if (volume.askuser(
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);
558 else
559 error = e_aborted;
561 return error;
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;
570 uint32 bloknr;
571 int okuser;
572 struct FileRequester *freq;
573 char mfname[FNSIZE], *t;
574 bool ok = false;
576 enterblock(ROOTBLOCK);
577 volume.showmsg("Checking rootblock\n");
578 if (rbl)
579 FreeBufMem(rbl);
581 if (!(rbl = (rootblock_t *)AllocBufMem (MAXRESBLOCKSIZE)))
583 adderror("couldn't allocate memory for rootblock");
584 return e_out_of_memory;
587 // read rootblock
588 if ((error = c_GetBlock ((uint8 *)rbl, ROOTBLOCK + volume.firstblock, volume.blocksize)))
590 adderror("rootblock could not be loaded");
591 return error;
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)))
605 return error;
607 volume.askuser(
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");
628 else
630 volume.showmsg("no mountlist written\n");
632 } while (!ok);
634 FreeAslRequest(freq);
635 volume.askuser("Now starting to check/repair\n"
636 "relocated partition", "CONTINUE", NULL);
638 return GetRootBlock();
640 else
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",
646 "ok", "cancel");
648 if (okuser)
649 return BuildRootBlock_hub();
650 else
652 aborting = 1;
653 return e_aborted;
658 error = CheckRootBlock();
660 switch (error)
662 case e_none:
663 break;
665 case e_repartition:
666 if ((error = Repartition(volume.firstblock+ROOTBLOCK)))
667 return error;
669 volume.askuser(
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");
692 else
694 volume.showmsg("no mountlist written\n");
696 } while (!ok);
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:
705 return error;
707 default:
708 return BuildRootBlock_hub();
711 exitblock();
712 return e_none;
715 static bool MakeMountFile(char *fname)
717 FILE *mf;
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);
743 fclose(mf);
744 return true;
746 return false;
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)
758 ULONG modemask;
760 // check rootblock type
761 if (r->disktype != ID_PFS_DISK && r->disktype != ID_PFS2_DISK) {
762 if (ss.verbose)
763 volume.showmsg("Unexpected rootblock id 0x%08lx\n", r->disktype);
764 return false;
767 // check options
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) {
772 if (ss.verbose)
773 volume.showmsg("Unexpected rootblock options 0x%08lx\n", r->options);
774 return false;
777 return true;
781 /* check loaded rootblock
783 static error_t CheckRootBlock(void)
785 int error = 0;
786 bool dirty = false;
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
792 + MODE_LARGEFILE;
794 if (rbl->options & ~modemask)
796 adderror("Unknown options enabled. Ask for an upgrade.");
797 return e_options_error;
800 // check the fields
801 if (!rbl->diskname[0])
803 if (mode == check)
804 adderror("volume has no name");
805 else
807 fixederror("volume had no name");
808 rbl->diskname[0] = strlen("doctor");
809 strcpy((char *)&rbl->diskname[1], "doctor");
810 dirty = true;
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);
821 resblocksize = 1024;
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) {
828 resblocksize = 2048;
829 if (volume.disksize > MAXDISKSIZE2K)
830 resblocksize = 4096;
832 } else {
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);
846 fixederror(bericht);
847 rbl->reserved_blksize = resblocksize;
848 dirty = true;
851 volume.rescluster = resblocksize / volume.blocksize;
853 // size must match, else repartition
854 if (rbl->options & MODE_SIZEFIELD)
856 if(rbl->disksize != volume.disksize)
858 int32 difference;
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;
873 dirty = true;
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;
884 dirty = true;
887 if (dirty)
888 return c_WriteBlock((uint8 *)rbl, ROOTBLOCK + volume.firstblock, volume.blocksize);
890 return error;
894 /**************************************
895 * GetRootBlockExtension
896 **************************************/
898 /* check rootblock extension. Do 'easy fix'. Returns
899 * false if failure
901 static error_t GetRext(void)
903 error_t error;
904 uint32 bloknr, oldbloknr;
906 bloknr = rbl->extension;
907 enterblock(bloknr);
908 volume.showmsg("Checking rext\n");
910 if (bloknr)
912 if ((error = volume.getblock((cachedblock_t *)&rext, bloknr)))
913 return error;
916 if (!bloknr || rext.data->id != EXTENSIONID)
918 adderror("extension block has wrong id");
919 if (mode == repair)
921 volume.status(1, "Searching rext", 256);
922 oldbloknr = bloknr;
923 bloknr = SearchBlock(EXTENSIONID, 0, bloknr, 0, 0, 0);
924 if (bloknr)
926 sprintf(bericht, "replaced block %lu with backup %lu", oldbloknr, bloknr);
927 fixederror(bericht);
928 rbl->extension = bloknr;
929 return GetRext();
931 else
933 volume.showmsg("No replacement block found\n");
934 free (rext.data);
935 if ((error = BuildRext(&rext)))
936 adderror("building new rootblockextension failed");
937 else
938 fixederror("new rootblockextension created");
939 return error;
942 else
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);
955 if (mode == check)
956 adderror("MODE_EXTENSION is disabled");
957 else
958 fixederror("MODE_EXTENSION was disabled");
961 /* fnsize */
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);
967 if (mode == check)
968 adderror(bericht);
969 else
971 if (rext.data->fnsize < 30)
973 fixederror("reset filename size to 30");
974 rext.data->fnsize = 30;
976 else
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;
986 else
988 volume.fnsize = 32 - 1;
991 /* tbd fields */
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])
997 if (mode == check)
998 adderror("rootblock extension TBD not empty");
999 else
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");
1010 exitblock();
1011 return e_none;
1015 /* check loaded rootblock extension
1017 bool GetPFS2Revision(char *vstring)
1019 char buf[8];
1020 uint16 ver = rext.data->pfs2version >> 16;
1021 uint16 rev = rext.data->pfs2version & 0xffff;
1023 if (!rext.data)
1024 return false;
1026 if (ver < 16)
1027 strcpy(buf, "AFS");
1028 else
1029 if (ver == 16)
1030 if (rev < 22)
1031 strcpy(buf, "AFS");
1032 else
1033 strcpy(buf, "PFS-II");
1034 else if (ver >= 18)
1035 strcpy(buf, "PFS-III");
1036 else
1037 strcpy(buf, "PFS-II");
1039 sprintf(vstring, "%s %d.%d", buf, ver, rev);
1041 return true;
1046 /**************************************
1047 * RepairBootBlock
1048 **************************************/
1050 /* read and check bootblock (not store)
1052 static error_t RepairBootBlock(void)
1054 error_t error;
1055 cachedblock_t bootbl;
1057 enterblock(BOOTBLOCK);
1059 // read bootblock
1060 bootbl.data = calloc(1, MAXRESBLOCKSIZE);
1061 if ((error = volume.getblock ((cachedblock_t *)&bootbl, BOOTBLOCK)))
1063 adderror("bootblock could not be loaded");
1064 free (bootbl.data);
1065 return error;
1068 // check bootblock type
1069 if (bootbl.data->bootblock.disktype != ID_PFS_DISK)
1071 if (mode == check)
1072 adderror("bootblock has wrong ID");
1073 else
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");
1080 free (bootbl.data);
1081 return error;
1086 free(bootbl.data);
1087 exitblock();
1088 return e_none;
1092 /**************************************
1093 * RepairDeldir
1094 **************************************/
1096 /* Check plus fix deldir
1098 static error_t RepairDeldir(void)
1100 int i;
1101 bool remove;
1102 uint32 ddsize;
1103 error_t error;
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]);
1121 if (ss.verbose)
1123 sprintf(bericht, "DELDIR %d\n", i);
1124 volume.showmsg(bericht);
1127 remove = false;
1128 if (i <= ddsize)
1130 remove = true;
1131 if (dd_CheckBlock(rext.data->deldir[i], i))
1133 if ((error = ResBlockUsed(rext.data->deldir[i])))
1134 remove = true;
1135 else
1136 remove = false;
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);
1146 rextdirty = true;
1148 exitblock();
1150 else
1152 ddsize = min(ddsize, i+1);
1156 if (ddsize != rext.data->deldirsize)
1158 rext.data->deldirsize = ddsize;
1159 rextdirty = true;
1162 if (rbl->deldir)
1164 if (mode == check)
1165 adderror("reference to old deldir");
1166 else
1168 rbl->deldir = 0;
1169 rootdirty = true;
1170 fixederror("reference to old deldir removed");
1174 else /* old mode */
1176 if (!rbl->deldir)
1178 if (mode == check)
1179 adderror("deldir enabled, but missing");
1180 else
1182 fixederror("deldir enabled, but missing");
1183 rbl->options &= ~MODE_DELDIR;
1184 rootdirty = true;
1187 else
1189 remove = false;
1190 if (dd_CheckBlock(rbl->deldir, 0))
1192 if ((error = ResBlockUsed(rbl->deldir)))
1193 remove = true;
1195 else
1196 remove = true;
1198 if (remove && mode == repair)
1200 fixederror("deldir block removed\n");
1201 rbl->deldir = 0;
1202 rbl->options &= ~MODE_DELDIR;
1203 rootdirty = true;
1209 else /* deldir disabled */
1211 if (rext.data->deldirsize)
1213 if (mode == check)
1214 adderror("deldir size incorrect");
1215 else
1217 fixederror("deldir size incorrect");
1218 rext.data->deldirsize = 0;
1219 rextdirty = true;
1223 if (mode == repair)
1225 for (i=0; i<32; i++)
1227 if (rext.data->deldir[i])
1229 fixederror("deldir block removed");
1230 rext.data->deldir[i] = 0;
1231 rextdirty = true;
1236 if (rbl->deldir)
1238 if (mode == check)
1239 adderror("illegal deldir reference");
1240 else
1242 fixederror("deldir block removed");
1243 rbl->deldir = 0;
1244 rootdirty = true;
1249 if (rootdirty)
1250 c_WriteBlock((uint8 *)rbl, ROOTBLOCK + volume.firstblock, volume.blocksize);
1251 if (rextdirty)
1252 volume.writeblock((cachedblock_t *)&rext);
1254 return e_none;
1258 static bool dd_CheckBlock(uint32 bloknr, int seqnr)
1260 error_t error;
1261 c_deldirblock_t ddblk;
1262 int i, ddnr;
1263 int32 blocks;
1264 canode_t delnode;
1265 struct deldirentry *dde;
1266 ULONG size, high;
1268 volume.progress(0, 1);
1270 /* get block */
1271 ddblk.data = calloc(1, SIZEOF_RESBLOCK);
1272 if ((error = volume.getblock((cachedblock_t *)&ddblk, bloknr)))
1274 adderror("couldn't read deldirblock");
1275 free (ddblk.data);
1276 return false;
1279 /* check id */
1280 if (ddblk.data->id != DELDIRID)
1282 adderror("deldirblock error");
1283 free (ddblk.data);
1284 return false;
1287 if (ddblk.data->seqnr != seqnr)
1289 adderror("deldirblock error");
1290 free (ddblk.data);
1291 return false;
1294 // check entries
1295 for (i=0; i<31; i++)
1297 blocks = 0;
1298 dde = &ddblk.data->entries[i];
1299 if (!dde->anodenr)
1300 continue;
1302 /* syntax fix */
1303 if (ss.stage == syntax)
1305 for (ddnr = dde->anodenr; ddnr; ddnr = delnode.next)
1307 if (!GetAnode (&delnode, ddnr, false) || IsAnodeUsed(ddnr))
1309 if (mode == check)
1310 adderror("delfile anode error");
1311 else
1313 fixederror("delfile anode error");
1314 dde->anodenr = 0;
1315 volume.writeblock((cachedblock_t *)&ddblk);
1317 break;
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);
1327 if (mode == check)
1328 adderror(bericht);
1329 else
1331 fixederror(bericht);
1332 dde->anodenr = 0;
1333 volume.writeblock((cachedblock_t *)&ddblk);
1338 if (!dde->anodenr)
1339 continue;
1341 for (ddnr = dde->anodenr; ddnr; ddnr = delnode.next)
1343 GetAnode(&delnode, ddnr, false);
1344 /* mark anodes as used */
1345 if (ss.stage <= anodebitmap)
1346 AnodeUsed(ddnr);
1348 /* for dde only the anodes need to be checked */
1349 // if (ss.stage == doubledel && isAnodeDouble(ddnr))
1350 // dde->anodenr = 0;
1354 free(ddblk.data);
1355 return true;
1359 /**************************************
1360 * Directory tree checker L2
1361 **************************************/
1363 struct dirstack
1365 struct dirstack *parent;
1366 char name[FNSIZE];
1367 uint32 anodenr;
1368 char *objecttype;
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;
1392 objectname[0] = 0;
1393 if (!currentobject)
1394 return;
1395 ds = NULL;
1396 while (ds != currentobject)
1398 for (n = currentobject; n->parent != ds; n=n->parent);
1399 if (n->parent && n->parent->parent)
1400 b = stpcpy(b, "/");
1401 b = stpcpy(b, n->name);
1402 ds = n;
1406 static void fixedfileerror(char *errortxt)
1408 if (currentobject)
1410 GetObjectName();
1411 volume.showmsg(currentobject->objecttype);
1412 volume.showmsg(objectname);
1413 volume.showmsg("\n");
1415 if (mode == check)
1416 adderror(errortxt);
1417 else
1418 fixederror(errortxt);
1421 static void addfileerror(char *errortxt)
1423 if (currentobject)
1425 GetObjectName();
1426 volume.showmsg(currentobject->objecttype);
1427 volume.showmsg(objectname);
1428 volume.showmsg("\n");
1430 adderror(errortxt);
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 };
1440 error_t error;
1442 volume.status(0, "root", 256);
1443 volume.showmsg("Starting directory check\n");
1444 pushdirstack(&stackbottom);
1445 error = RepairDir(NULL, NULL);
1446 popdirstack();
1447 return error;
1451 static error_t RepairDir(struct direntry *de, c_dirblock_t *parent)
1453 uint32 mainanodenr, anodenr, parentanodenr;
1454 canode_t dirnode;
1455 error_t error = e_none;
1457 stats.numdirs++;
1458 if (de)
1460 volume.status(0, currentobject->name, 0);
1461 if (ss.verbose)
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)
1476 /* get anode */
1477 if (!GetAnode(&dirnode, anodenr, true))
1478 return e_remove;
1480 /* check anode */
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);
1490 exitblock();
1491 switch (error)
1493 case e_empty:
1495 // BUG: an empty leading dirblock cannot be freed like
1496 // that, the anodes have to moved!
1498 // if (!dirnode.next)
1499 // {
1500 ResBlockUsed(dirnode.blocknr);
1501 AnodeUsed(anodenr);
1502 error = e_none;
1503 break;
1504 // }
1506 // fixedfileerror("empty directory block");
1508 case e_remove:
1510 if (error != e_empty)
1512 if (mode == repair)
1513 fixedfileerror("removing corrupt directory block");
1514 else
1515 addfileerror("corrupt directory block");
1518 DeleteAnode(mainanodenr, anodenr);
1519 break;
1521 case e_none:
1523 ResBlockUsed(dirnode.blocknr);
1524 AnodeUsed(anodenr);
1525 break;
1527 default:
1529 KillReservedBitmap();
1532 if ((error != e_none) || aborting)
1533 return error;
1536 return e_none;
1539 static error_t RepairDirBlock(uint32 bloknr, uint32 anodenr, uint32 parent)
1541 c_dirblock_t dirblk;
1542 struct direntry *entry;
1543 error_t error;
1545 /* get block */
1546 dirblk.data = calloc(1, SIZEOF_RESBLOCK);
1547 if ((error = volume.getblock((cachedblock_t *)&dirblk, bloknr)))
1549 free (dirblk.data);
1550 return e_remove;
1553 /* check dirblock */
1554 if (dirblk.data->id != DBLKID || dirblk.data->anodenr != anodenr ||
1555 dirblk.data->parent != parent)
1557 free (dirblk.data);
1558 return e_remove;
1561 entry = (struct direntry *)dirblk.data->entries;
1563 while (entry->next)
1565 if ((error = RepairDirEntry(entry, &dirblk)))
1567 if (mode == repair)
1569 redosyntax = true;
1570 fixedfileerror("removing corrupt directory entry");
1571 RemoveDirEntry(entry, &dirblk);
1573 else
1575 addfileerror("corrupt directory entry");
1576 entry = NEXTENTRY(entry);
1579 else
1580 entry = NEXTENTRY(entry);
1583 /* has to be done after main check, because an empty block can
1584 * arise
1586 error = e_none;
1587 if (mode == repair)
1589 entry = (struct direntry *)dirblk.data->entries;
1590 if (!entry->next)
1591 error = e_empty;
1594 free (dirblk.data);
1595 return error;
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)
1605 return e_empty;
1607 if (ss.stage == syntax)
1609 if (de->next & 1)
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;
1640 switch (de->type)
1642 case ST_USERDIR:
1644 dirstack.objecttype = dirtype;
1645 error = RepairDir(de, dirblk);
1646 break;
1648 case ST_SOFTLINK:
1650 dirstack.objecttype = softlinktype;
1651 error = RepairSoftLink(de, dirblk);
1652 break;
1654 case ST_LINKFILE:
1655 case ST_LINKDIR:
1657 dirstack.objecttype = hardlinktype;
1658 error = RepairHardLink(de, dirblk);
1659 if (error == e_remove)
1660 redosyntax = true;
1661 break;
1663 case ST_ROLLOVERFILE:
1665 dirstack.objecttype = rollovertype;
1666 error = RepairRollover(de, dirblk);
1667 break;
1669 case ST_FILE:
1671 dirstack.objecttype = filetype;
1672 error = RepairFile(de, dirblk);
1673 break;
1675 case ST_PIPEFILE:
1676 case ST_ROOT:
1677 default:
1679 addfileerror("invalid filetype");
1680 error = e_direntry_error;
1681 break;
1684 popdirstack();
1685 return error;
1688 static error_t RepairFile(struct direntry *de, c_dirblock_t *parent)
1690 int32 blokken;
1691 struct extrafields extra;
1692 canode_t filenode;
1693 error_t error;
1694 uint32 anodenr, bl;
1695 ULONG size, high;
1697 stats.numfiles++;
1698 if ((error = GetExtraFields(&extra, de)))
1699 return error;
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");
1712 blokken = 0;
1713 for (anodenr = de->anode; anodenr; anodenr = filenode.next)
1715 if ((error = CheckAnode(&filenode, anodenr, true)))
1716 return e_remove;
1718 blokken += filenode.clustersize;
1721 size = GetDEFileSize(de, &extra, &high);
1722 if (!FileSizeCheck(size, high, blokken))
1724 addfileerror("invalid filesize");
1725 return e_remove;
1729 if (extra.link)
1730 RepairLinkChain(de, parent);
1732 /* bitmap gen */
1733 for (anodenr = de->anode; anodenr; anodenr = filenode.next)
1735 GetAnode(&filenode, anodenr, true);
1736 if ((error = AnodeUsed(anodenr)))
1737 break;
1739 for (bl = filenode.blocknr; bl < filenode.blocknr + filenode.clustersize; bl++)
1740 if ((error = MainBlockUsed(bl)))
1741 break;
1744 if (error != e_none)
1746 /* invalidate bitmaps to force generation in next stage. */
1747 InvalidBitmap(volume.mainbitmap);
1748 InvalidBitmap(volume.anodebitmap);
1749 return error;
1752 return e_none;
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;
1761 canode_t linknode;
1762 error_t error;
1764 stats.numhardlink++;
1765 if ((error = GetExtraFields(&extra, de)))
1766 return e_remove;
1768 if (!extra.link)
1770 addfileerror("invalid hardlink");
1771 return e_remove;
1774 /* get linknode */
1775 if (!GetAnode (&linknode, de->anode, true))
1776 return e_remove;
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");
1783 return e_remove;
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))
1794 case 0:
1795 addfileerror("dangling hardlink");
1796 return e_remove;
1798 case ST_FILE:
1799 case ST_ROLLOVERFILE:
1800 case ST_SOFTLINK:
1801 case ST_LINKFILE:
1802 if (de->type == ST_LINKDIR)
1804 fixedfileerror("invalid hardlink");
1805 de->type = ST_LINKFILE;
1806 volume.writeblock((cachedblock_t *)dirblok);
1808 break;
1810 default:
1811 if (de->type == ST_LINKFILE)
1813 fixedfileerror("invalid hardlink");
1814 de->type = ST_LINKDIR;
1815 volume.writeblock((cachedblock_t *)dirblok);
1817 break;
1820 if ((error = AnodeUsed(de->anode)))
1821 return error;
1823 return e_none;
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;
1839 error_t error;
1841 stats.numrollover++;
1842 if ((error = GetExtraFields(&extra, de)))
1843 return error;
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);
1859 * Helper functions
1862 static error_t RemoveDirEntry(struct direntry *de, c_dirblock_t *dirblk)
1864 uint8 *dest, *source;
1865 uint32 movelen;
1867 dest = (uint8 *)de;
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);
1875 else
1876 return e_fatal_error;
1878 return e_none;
1882 /* remove node from anodechain
1884 static error_t DeleteAnode(uint32 anodechain, uint32 node)
1886 canode_t prev_node, next_node;
1887 uint32 previous;
1889 /* node is head */
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);
1900 else
1902 /* find previous */
1903 previous = anodechain;
1904 while (true)
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);
1920 return e_none;
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);
1929 uint16 flags, i;
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
1937 if (flags)
1938 addfileerror("unknown extrafield flags found (ignored)");
1940 // patch protection lower 8 bits
1941 extrafields->prot |= de->protection;
1942 return e_none;
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;
1954 uint32 movelen;
1955 int diff;
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);
1987 orvalue = 1;
1988 /* fill packed field array */
1989 for (i = 0; i < sizeof(struct extrafields) / 2; i++)
1991 if (*fields)
1993 array[j++] = *fields++;
1994 flags |= orvalue;
1996 else
1998 fields++;
2001 orvalue <<= 1;
2004 /* add fields to direntry */
2005 i = j;
2006 while (i)
2007 *dirext++ = array[--i];
2008 *dirext++ = flags;
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;
2019 canode_t linknode;
2020 error_t error;
2021 uint32 parent;
2023 /* check extra fields */
2024 if ((error = GetExtraFields(&extra, de)))
2025 return error;
2027 /* check if object has a linkchain */
2028 if (!extra.link)
2029 return e_none;
2031 if (!GetAnode(&linknode, extra.link, false))
2032 return e_anode_error;
2034 parent = dirblk->data->anodenr;
2035 for (;;)
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))
2052 extra.link = 0;
2053 SetExtraFields(&extra, de, dirblk);
2057 if (!linknode.next)
2058 return e_none;
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))
2071 return e_empty;
2073 if (anode->clustersize == 0 && anode->blocknr == 0 && anode->next == 0)
2074 return e_empty;
2076 return e_none;
2079 /* Search file by anodenr in a directory
2080 * return filetype or 0 for not found
2082 int SearchInDir(uint32 diranodenr, uint32 target)
2084 canode_t anode;
2085 c_dirblock_t dirblk;
2086 struct direntry *de;
2087 error_t error = e_none;
2088 int ftype;
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))
2095 break;
2097 if ((error = volume.getblock((cachedblock_t *)&dirblk, anode.blocknr)) || aborting)
2098 break;
2100 de = FIRSTENTRY(&dirblk);
2101 while (de->next)
2103 if (de->anode == target)
2105 ftype = de->type;
2106 free (dirblk.data);
2107 return ftype;
2110 de = NEXTENTRY(de);
2113 diranodenr = anode.next;
2116 free (dirblk.data);
2117 return 0;
2120 /**************************************
2121 * Anode tree checker L2
2122 **************************************/
2124 /* Check anode tree.
2125 * Returns fatal errors (e_none = continue)
2127 static error_t RepairAnodeTree(void)
2129 int i;
2130 error_t error;
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)
2143 return error;
2145 if (rext.data->superindex[i] != child_blk_nr)
2146 volume.writeblock((cachedblock_t *)&rext);
2150 else
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)
2159 return error;
2161 if (rbl->idx.small.indexblocks[i] != child_blk_nr)
2162 c_WriteBlock((uint8 *)rbl, ROOTBLOCK + volume.firstblock, volume.blocksize);
2167 return e_none;
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;
2188 uint32 oldbloknr;
2190 // get anodeblock
2191 ablk.data = calloc(1, SIZEOF_RESBLOCK);
2192 if (*bloknr)
2194 if ((error = volume.getblock((cachedblock_t *)&ablk, *bloknr)))
2196 free (ablk.data);
2197 return error;
2200 enterblock(*bloknr);
2203 // check syntax block
2204 if (ss.stage == syntax)
2206 if (ablk.data->id != ABLKID || ablk.data->seqnr != seqnr)
2208 if (*bloknr)
2210 sprintf(bericht, "anodeblock seqnr %lu blocknr %lu has an incorrect id", seqnr, *bloknr);
2211 adderror(bericht);
2214 if (mode == repair)
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);
2223 else
2225 /* remove corrupt block */
2226 fixederror("no replacement found - removing block");
2227 free (ablk.data);
2228 exitblock();
2229 return e_remove;
2235 ResBlockUsed(*bloknr);
2236 free (ablk.data);
2237 exitblock();
2238 return error;
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;
2251 uint32 i, num;
2252 uint32 blknr;
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];
2262 if (i < num)
2264 /* force bitmapindexblock to be searched and created */
2265 if (!blknr)
2266 rbl->idx.large.bitmapindex[i] = rbl->lastreserved;
2268 if ((error = RepairBitmapIndex(&rbl->idx.large.bitmapindex[i], i)) || aborting)
2269 return error;
2271 if (rbl->idx.large.bitmapindex[i] != blknr)
2272 c_WriteBlock((uint8 *)rbl, ROOTBLOCK + volume.firstblock, volume.blocksize);
2276 return e_none;
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;
2292 uint32 oldbloknr;
2294 // get anodeblock
2295 bmblk.data = calloc(1, SIZEOF_RESBLOCK);
2296 if (GetBuildBlock(BMBLKID, seqnr))
2297 return e_none;
2299 if (*bloknr)
2301 if ((error = volume.getblock((cachedblock_t *)&bmblk, *bloknr)))
2303 free (bmblk.data);
2304 return error;
2308 enterblock(*bloknr);
2310 // check syntax block
2311 if (ss.stage == syntax)
2313 if (bmblk.data->id != BMBLKID || bmblk.data->seqnr != seqnr)
2315 if (*bloknr)
2317 sprintf(bericht, "bitmapblock seqnr %lu blocknr %lu has an incorrect id", seqnr, *bloknr);
2318 adderror(bericht);
2321 if (mode == repair)
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);
2330 else
2332 volume.showmsg("No replacement block found\n");
2333 free (bmblk.data);
2334 error = BuildBitmapBlock(&bmblk, seqnr);
2335 exitblock();
2336 if (error)
2337 adderror("building new bitmapblock failed");
2338 else
2339 fixederror("new bitmapblock created");
2340 return error;
2346 ResBlockUsed(*bloknr);
2347 free (bmblk.data);
2348 exitblock();
2349 return error;
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;
2362 int i;
2363 uint32 child_blk_nr, oldbloknr;
2365 enterblock(*bloknr);
2367 if ((cblk = GetBuildBlock(bloktype, seqnr)))
2368 iblk = *(c_indexblock_t *)cblk;
2370 if (!iblk.data)
2372 iblk.data = calloc(1, SIZEOF_RESBLOCK);
2374 /* read or build indexblock
2376 if ((error = volume.getblock((cachedblock_t *)&iblk, *bloknr)))
2378 free (iblk.data);
2379 return error;
2382 /* check id */
2383 if (ss.stage == syntax)
2385 if (iblk.data->id != bloktype || iblk.data->seqnr != seqnr)
2387 if (*bloknr)
2389 sprintf(bericht,
2390 "indexblock %lu blocknr %lu type %x has incorrect id of %x, %lu",
2391 seqnr, *bloknr, bloktype, iblk.data->id, iblk.data->seqnr);
2392 adderror(bericht);
2395 if (mode == repair)
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);
2403 free (iblk.data);
2404 return RepairIndexBlock(bloktype, repairchild, bloknr, seqnr);
2406 else
2408 volume.showmsg("No replacement block found\n");
2409 free (iblk.data);
2410 if ((error = BuildIndexBlock(&iblk, bloktype, seqnr)))
2412 adderror("building new indexblock failed");
2413 exitblock();
2414 return error;
2416 fixederror("new indexblock created");
2419 else
2421 /* check mode failure */
2422 ResBlockUsed(*bloknr);
2423 free(iblk.data);
2424 return e_none;
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))
2437 case e_none:
2438 break;
2440 default:
2441 /* kill block */
2442 iblk.data->index[i] = 0;
2443 break;
2446 if (aborting)
2447 return error;
2449 /* save changes */
2450 if (child_blk_nr != iblk.data->index[i] && iblk.mode == check)
2451 volume.writeblock((cachedblock_t *)&iblk);
2455 exitblock();
2456 if (iblk.mode == check)
2458 /* not necessary (allowed) for generated blocks */
2459 ResBlockUsed(*bloknr);
2460 free (iblk.data);
2462 return error;
2466 /**************************************
2467 * Bitmap Generator L3
2468 **************************************/
2470 // public data
2472 // enable flags
2474 // public functions
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);
2495 adderror(bericht);
2497 if (!(bloknr = SearchLastReserved(&volume)))
2498 return e_fatal_error;
2500 fixederror(NULL);
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;
2516 if (mode == check)
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);
2528 return e_none;
2531 /* assumes valid anodetree syntax
2533 static error_t InitAnodeBitmap(void)
2535 c_indexblock_t iblk;
2536 int i, s;
2537 error_t error;
2539 KillAnodeBitmap();
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)))
2552 free (iblk.data);
2553 return error;
2556 for (i=INDEX_PER_BLOCK - 1; !iblk.data->index[i]; i--);
2558 else
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++)
2567 AnodeUsed(i);
2569 free (iblk.data);
2570 return e_none;
2573 /* Initialise generation of main bitmap
2575 static error_t InitMainBitmap(void)
2577 KillMainBitmap();
2578 volume.mainbitmap = bg_InitBitmap(rbl->lastreserved+1,
2579 volume.lastblock-volume.firstblock, 1);
2581 if (!volume.mainbitmap)
2582 return e_fatal_error;
2583 else
2584 return e_none;
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.
2604 * Pre:
2605 * - syntax disk is correct
2606 * - rootblock read
2607 * - reserved bitmap generated AND valid
2609 static error_t RepairReservedBitmap(void)
2611 rootblock_t *lrb;
2612 bitmapblock_t *bitmap;
2613 uint32 i, j, mask, blknr, blocksfree = 0;
2614 bool dirty = false;
2615 error_t error;
2616 uint32 nuba=0, ubna=0;
2617 uint8 *t;
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)))
2623 return error;
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;
2629 t = (uint8 *)lrb;
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");
2635 FreeBufMem(lrb);
2636 return error;
2638 t += volume.blocksize;
2641 bitmap = (bitmapblock_t *)(lrb + 1);
2642 if (bitmap->id != BMBLKID)
2644 /* this is also done at BUILD ROOTBLOCK */
2645 if (mode == check)
2646 adderror("reserved bitmap id is wrong");
2647 else
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++)
2657 if (!(i&0xff))
2659 if (aborting)
2660 break;
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)
2676 nuba++;
2677 sprintf(bericht, "reserved block %lu not used but allocated", blknr);
2678 if (ss.verbose)
2679 fixederror(bericht);
2680 lrb->reserved_free++;
2682 else
2684 ubna++;
2685 sprintf(bericht, "reserved block %lu used but not allocated", blknr);
2686 if (ss.verbose)
2687 fixederror(bericht);
2688 lrb->reserved_free--;
2691 bitmap->bitmap[i] ^= mask;
2692 dirty = true;
2695 if (bitmap->bitmap[i] & mask)
2696 blocksfree++;
2701 if (nuba > 0)
2703 sprintf(bericht, "%lu reserved blocks not used but allocated", nuba);
2704 if (mode == check)
2705 fixederror(bericht);
2708 if (ubna > 0)
2710 sprintf(bericht, "%lu reserved blocks used but not allocated", ubna);
2711 if (mode == check)
2712 fixederror(bericht);
2715 // check blocks free
2716 if (lrb->reserved_free != blocksfree && !aborting)
2718 if (mode == check)
2719 fixederror("wrong number of reserved blocks free");
2720 lrb->reserved_free = blocksfree;
2721 dirty = true;
2724 error = e_none;
2725 if (dirty && !aborting)
2727 t = (uint8 *)lrb;
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);
2736 FreeBufMem(lrb);
2737 return error;
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;
2751 bitmap_t *gbm;
2752 error_t error = e_none;
2753 bool dirty;
2754 bool build = 0;
2755 uint32 nuba=0, ubna=0;
2757 if (ss.verbose)
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)
2770 free (bmb.data);
2771 if ((error = BuildBitmapBlock(&bmb, bmseqnr)))
2772 return error;
2773 build = 1;
2776 // check block
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)
2791 nuba++;
2792 // sprintf(bericht, "block %d not used but allocated", blknr);
2793 // if (ss.verbose)
2794 // fixederror(bericht);
2795 rbl->blocksfree++;
2797 else
2799 ubna++;
2800 // sprintf(bericht, "block %d used but not allocated", blknr);
2801 // if (ss.verbose)
2802 // fixederror(bericht);
2803 rbl->blocksfree--;
2806 bmb.data->bitmap[i] ^= mask;
2807 dirty = true;
2808 if ((error = volume.writeblock ((cachedblock_t *)&bmb)))
2810 free (bmb.data);
2811 return error;
2815 if (bmb.data->bitmap[i] & mask)
2816 blocksfree++;
2822 if (nuba > 0)
2824 sprintf(bericht, "%lu data blocks not used but allocated", nuba);
2825 fixederror(bericht);
2828 if (ubna > 0)
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;
2839 dirty = true;
2842 if (dirty)
2843 error = c_WriteBlock ((uint8 *)rbl, ROOTBLOCK + volume.firstblock, volume.blocksize);
2845 if (!build)
2846 free (bmb.data);
2847 return error;
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)
2858 uint32 i, anodenr;
2859 int anodeused;
2860 canode_t anode;
2861 bitmap_t *gbm = volume.anodebitmap;
2862 error_t error;
2863 uint32 nuba=0, ubna=0;
2865 if (ss.verbose)
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++)
2871 if (!(i%32))
2873 if (aborting)
2874 break;
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)
2885 if (anodeused)
2887 if (ss.verbose)
2889 sprintf(bericht, "anode %#lx used but not allocated", anodenr);
2890 fixederror(bericht);
2893 ubna++;
2894 if (mode == repair)
2896 anode.clustersize = 0;
2897 anode.blocknr = 0xffffffff;
2898 anode.next = 0;
2899 SaveAnode(&anode, anodenr);
2902 else
2904 if (ss.verbose)
2906 sprintf(bericht, "anode %#lx not used but allocated", anodenr);
2907 fixederror(bericht);
2910 nuba++;
2911 if (mode == repair)
2913 anode.clustersize =
2914 anode.blocknr =
2915 anode.next = 0;
2916 SaveAnode(&anode, anodenr);
2922 if (nuba > 0)
2924 sprintf(bericht, "%lu anodes not used but allocated", nuba);
2925 fixederror(bericht);
2928 if (ubna > 0)
2930 sprintf(bericht, "%lu anodes used but not allocated", ubna);
2931 fixederror(bericht);
2934 return e_none;
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);
2947 adderror(bericht);
2950 return error;
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);
2966 return error;
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);
2983 return error;
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
2997 * stepsize step
2999 static bitmap_t *bg_InitBitmap(int32 start, int32 stop, int32 step)
3001 bitmap_t *mybitmap;
3003 if (!(mybitmap = calloc(1, sizeof(bitmap_t))))
3004 return NULL;
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)))
3013 free(mybitmap);
3014 volume.showmsg("DOCTOR ERROR: out of memory\n");
3015 return NULL;
3018 memset(mybitmap->map, 0xff, mybitmap->lwsize*4);
3019 mybitmap->valid = true;
3020 return(mybitmap);
3023 static void bg_KillBitmap(bitmap_t **bm)
3025 if (*bm)
3027 if ((*bm)->map)
3028 free((*bm)->map);
3029 free(*bm);
3032 *bm = NULL;
3035 static error_t bg_ItemUsed(bitmap_t *bm, uint32 nr)
3037 uint32 index, bit;
3039 if (!bm)
3040 return e_none;
3042 if (nr < bm->start || nr > bm->stop)
3043 return e_outside_bitmap_error;
3045 nr -= bm->start;
3046 nr /= bm->step;
3047 index = nr/32;
3048 bit = nr%32;
3050 // check & set bit
3051 if (bm->map[index] & (0x80000000UL >> bit))
3053 bm->map[index] ^= (0x80000000UL >> bit);
3054 return e_none;
3056 else
3058 return e_double_allocation;
3062 static BOOL bg_IsItemUsed(bitmap_t *bm, uint32 nr)
3064 uint32 index, bit;
3066 nr -= bm->start;
3067 nr /= bm->step;
3068 index = nr/32;
3069 bit = nr%32;
3071 if (bm->map[index] & (0x80000000UL >> bit))
3072 return FALSE;
3073 else
3074 return TRUE;