Added a test for MUIA_Listview_SelectChange.
[AROS.git] / rom / filesys / pfs3 / pfsdoctor / fullscan.c
blobe4727c40dc2e6badd218374e6df93976d74d7c65
1 /* $Id$ */
2 /* $Log: fullscan.c $
3 * Revision 2.5 1999/09/10 22:14:49 Michiel
4 * Bugfixes etc (1.4)
6 * Revision 2.4 1999/05/07 16:49:00 Michiel
7 * bugfixes etc
9 * Revision 2.3 1999/05/04 17:59:09 Michiel
10 * check mode, logfile, search rootblock implemented
11 * bugfixes
13 * Revision 2.2 1999/05/04 04:27:13 Michiel
14 * debugged upto buildrext
16 * Revision 2.1 1999/04/30 12:17:58 Michiel
17 * Accepts OK disks, bitmapfix and hardlink fix works
19 * Revision 1.1 1999/04/22 15:25:10 Michiel
20 * Initial revision
21 * */
23 #define __USE_SYSBASE
24 #include <string.h>
25 #include <math.h>
27 #include "pfs3.h"
28 #include "doctor.h"
29 #include <proto/exec.h>
30 #include <proto/dos.h>
31 #include <clib/alib_protos.h>
32 #include <dos/dos.h>
33 #include <stdlib.h>
35 uint32 maxdatestamp = 0;
37 void InitFullScan(void)
39 NewList((struct List *)&volume.buildblocks);
42 /* free mem etc */
43 void ExitFullScan(void)
45 buildblock_t *bbl, *next;
47 for (bbl = HeadOf(&volume.buildblocks); (next=bbl->next); bbl=next)
49 if (bbl->b.data)
50 FreeBufMem(bbl->b.data);
51 free (bbl);
55 /* Allocate create blocks. Write them to the cache and free
56 * memory.
57 * pre: resbitmap ready and valid
59 error_t AllocBuildBlocks(void)
61 buildblock_t *bbl, *next;
62 cachedblock_t tblk;
63 error_t error = e_none;
64 uint32 blocknr, offset, seqnr;
65 uint16 type;
67 for (bbl = HeadOf(&volume.buildblocks); bbl->next; bbl=next)
69 volume.progress(0, 1);
70 next = bbl->next;
71 blocknr = fs_AllocResBlock();
72 if (blocknr)
74 bbl->b.blocknr = blocknr;
75 bbl->b.mode = done;
76 volume.writeblock(&bbl->b);
77 switch(bbl->b.data->id)
79 case EXTENSIONID:
80 rbl->extension = blocknr;
81 c_WriteBlock((uint8 *)rbl, ROOTBLOCK + volume.firstblock, volume.blocksize);
82 rext.mode = check;
83 rext.data = calloc(1, SIZEOF_RESBLOCK);
84 rext.blocknr = blocknr;
85 memcpy(rext.data, bbl->b.data, SIZEOF_RESBLOCK);
86 break;
88 case SBLKID:
89 rext.data->superindex[bbl->b.data->indexblock.seqnr] = blocknr;
90 volume.writeblock((cachedblock_t *)&rext);
91 break;
93 case BMIBLKID:
94 rbl->idx.large.bitmapindex[bbl->b.data->indexblock.seqnr] = blocknr;
95 c_WriteBlock((uint8 *)rbl, ROOTBLOCK + volume.firstblock, volume.blocksize);
96 break;
98 case IBLKID:
99 if (!(rbl->options & MODE_SUPERDELDIR))
101 rbl->idx.small.indexblocks[bbl->b.data->indexblock.seqnr] = blocknr;
102 c_WriteBlock((uint8 *)rbl, ROOTBLOCK + volume.firstblock, volume.blocksize);
103 break;
105 type = SBLKID;
107 case BMBLKID:
108 if (bbl->b.data->id == BMBLKID)
109 type = BMIBLKID;
111 seqnr = bbl->b.data->indexblock.seqnr/INDEX_PER_BLOCK;
112 offset = bbl->b.data->indexblock.seqnr%INDEX_PER_BLOCK;
113 tblk.data = calloc(1, SIZEOF_RESBLOCK);
114 if (tblk.data)
116 GetResBlock(&tblk, type, seqnr, true);
117 tblk.data->indexblock.index[offset] = blocknr;
118 volume.writeblock(&tblk);
119 free(tblk.data);
121 else
123 adderror("memory allocation error");
124 return e_out_of_memory;
126 break;
129 MinRemove(bbl);
130 FreeBufMem(bbl->b.data);
131 free(bbl);
133 else
135 adderror("allocation error");
136 error = e_alloc_fail;
140 return error;
143 /* Allocate a block from the generated reserved bitmap.
144 * This reserved bitmap must be complete and valid
146 uint32 fs_AllocResBlock(void)
148 uint32 i, field, blocknr;
149 int32 j;
151 for (i=0; i<volume.resbitmap->lwsize; i++)
153 field = volume.resbitmap->map[i];
154 if (field)
156 for (j=31; j>=0; j--)
158 if (field & (1 << j))
160 blocknr = rbl->firstreserved + (i*32+(31-j))*volume.rescluster;
161 if (blocknr < rbl->lastreserved)
163 volume.resbitmap->map[i] &= ~(1 << j);
164 return blocknr;
171 /* reserved area full */
172 return 0;
175 /* Redefine volume from rootblock located at 'bloknr'
177 error_t Repartition(uint32 bloknr)
179 rootblock_t *rbl;
180 error_t error = e_none;
182 if (!(rbl = (rootblock_t *)AllocBufMem (MAXRESBLOCKSIZE)))
183 return e_out_of_memory;
185 // read rootblock
186 error = c_GetBlock ((uint8 *)rbl, ROOTBLOCK + volume.firstblock, volume.blocksize);
187 if (error)
188 goto ret_error;
190 if (!IsRootBlock(rbl) || !rbl->disksize)
192 error = e_syntax_error;
193 goto ret_error;
196 volume.firstblock = bloknr - ROOTBLOCK;
197 volume.lastblock = volume.firstblock + rbl->disksize - 1;
198 volume.disksize = rbl->disksize;
199 volume.lastreserved = rbl->lastreserved;
200 volume.repartitioned = true;
202 ret_error:
204 FreeBufMem(rbl);
205 return error;
208 /* special case: no alloc needed */
209 error_t BuildBootBlock(void)
211 bootblock_t *bbl;
212 error_t error;
214 if (!(bbl = AllocBufMem(2*volume.blocksize)))
215 return e_out_of_memory;
217 memset (bbl, 0, 2*volume.blocksize);
218 bbl->disktype = ID_PFS_DISK;
219 error = c_WriteBlock ((UBYTE *)bbl, 1, BOOTBLOCK + volume.firstblock);
220 FreeBufMem (bbl);
221 return error;
224 /* special case: no alloc needed
225 * Create rootblock. The datestamp is set to the highest value found by
226 * SeachBlocks, increased by 0x299. All references are uptodate.
228 error_t BuildRootBlock(rootblock_t *rbl)
230 struct DateStamp time;
231 uint32 i, j;
232 scanelement_t ind[104];
233 uint32 resblocksize = 1024;
235 volume.status(0, "Building rootblock", 3);
236 memset (rbl, 0, volume.blocksize);
237 DateStamp (&time);
239 rbl->disktype = ID_PFS_DISK;
240 rbl->options = MODE_HARDDISK | MODE_SPLITTED_ANODES | MODE_DIR_EXTENSION |
241 MODE_SIZEFIELD | MODE_DATESTAMP | MODE_EXTROVING;
242 #if LARGE_FILE_SIZE
243 rbl->options |= MODE_LARGEFILE;
244 rbl->disktype = ID_PFS2_DISK;
245 #endif
247 rbl->disksize = volume.disksize;
248 if (volume.disksize > MAXSMALLDISK) {
249 rbl->options |= MODE_SUPERINDEX;
250 if (volume.disksize > MAXDISKSIZE1K) {
251 rbl->disktype = ID_PFS2_DISK;
252 resblocksize = 2048;
253 if (volume.disksize > MAXDISKSIZE2K)
254 resblocksize = 4096;
258 rbl->datestamp = ~0; // don't be a break on search functions
259 rbl->creationday = (UWORD)time.ds_Days;
260 rbl->creationminute = (UWORD)time.ds_Minute;
261 rbl->creationtick = (UWORD)time.ds_Tick;
262 rbl->protection = 0xf0;
263 rbl->firstreserved = 2;
264 rbl->lastreserved = SearchLastReserved(&volume);
265 volume.progress(0,1);
266 rbl->reserved_free = (rbl->lastreserved - rbl->firstreserved)/volume.rescluster;
268 rbl->reserved_blksize = resblocksize;
269 rbl->blocksfree = volume.disksize - rbl->lastreserved;
270 rbl->alwaysfree = rbl->blocksfree/20;
272 rbl->diskname[0] = strlen("FixedDisk");
273 memcpy(rbl->diskname+1, "FixedDisk", strlen("FixedDisk"));
275 /* extension is created by build extension */
277 /* create bitmap index */
278 memset (ind, 0, 104*sizeof(scanelement_t));
279 volume.status(1, "Searching bitmap blocks", rbl->lastreserved - 2);
280 SearchBlocks(ind, 0, 103, rbl->firstreserved, rbl->lastreserved, BMIBLKID);
281 volume.progress(0,1);
282 if (rbl->options & MODE_SUPERINDEX)
283 j = 104;
284 else
285 j = 5;
287 for (i=0; i<j; i++)
288 rbl->idx.large.bitmapindex[i] = ind[i].blocknr;
290 /* create anodeindex */
291 if (!(rbl->options & MODE_SUPERINDEX))
293 memset (ind, 0, 104*sizeof(scanelement_t));
294 volume.status(1,"Searching index blocks", rbl->lastreserved - 2);
295 SearchBlocks(ind, 0, 98, rbl->firstreserved, rbl->lastreserved, IBLKID);
296 for (i=0; i<99; i++)
297 rbl->idx.small.indexblocks[i] = ind[i].blocknr;
299 rbl->datestamp = maxdatestamp + 0x200;
300 volume.progress(0,1);
301 volume.status(1, " ", 100);
302 return e_none;
305 /* Search deldirblocks, indexblocks, anodeblocks, bitmapblocks
306 * el = preallocated and cleared array of scanelement for storing result
307 * seqlow = lowest element array
308 * seqhigh = highest element array
309 * start = first blocknr
310 * stop = last blocknr
312 void SearchBlocks(scanelement_t el[], uint32 seqlow, uint32 seqhigh,
313 uint32 start, uint32 stop, uint16 bloktype)
315 cachedblock_t blk;
316 uint32 i, seqnr, ds = 0;
318 blk.data = calloc(1, SIZEOF_RESBLOCK);
319 volume.status(1, NULL, (stop-start)/volume.rescluster);
320 for (i = start; i < stop; i+=volume.rescluster)
322 volume.progress(1,1);
323 if (volume.getblock(&blk, i))
324 continue;
326 if (aborting)
328 volume.showmsg("Aborting block search\n");
329 aborting = 0;
330 break;
333 if (blk.data->id == bloktype)
335 seqnr = blk.data->indexblock.seqnr;
336 ds = blk.data->indexblock.datestamp;
337 if (seqnr >= seqlow && seqnr <= seqhigh &&
338 ds >= el[seqnr-seqlow].datestamp)
340 el[seqnr-seqlow].blocknr = i;
341 el[seqnr-seqlow].datestamp = ds;
342 maxdatestamp = max(ds, maxdatestamp);
347 free (blk.data);
348 volume.status(1," ",100);
351 /* search for a block on a volume.
352 * bloktype - kind of block to look for
353 * seqnr - longword on offset 8 (not for REXT)
354 * last - blocknr. Max is last + 32
355 * datestamp - maximum datestamp on offset 4, 0 = no max
356 * anodenr, parent - for dirblocks only, 0 = ignore
357 * returns bloknr
359 * bloktypes: REXT, BM, BMI, S, AI, A, D
361 uint32 SearchBlock(uint16 bloktype, uint32 seqnr, uint32 last, uint32 datestamp, uint32 anodenr,
362 uint32 parent)
364 cachedblock_t blk;
365 uint32 ds, tmp;
366 int32 i, bloknr; // signed !!
367 int found = 0;
369 blk.data = calloc(1, SIZEOF_RESBLOCK);
370 bloknr = ds = 0;
371 if (last)
373 last += 64;
374 last = min(rbl->lastreserved, last);
376 else
377 last = rbl->lastreserved;
378 last -= (last % volume.rescluster);
380 if (!datestamp)
381 datestamp = rbl->datestamp;
383 volume.status(1,NULL,1024);
384 for (i = last; i != last+volume.rescluster; i -= volume.rescluster)
386 /* rollover to end of reserved area */
387 if (i < rbl->firstreserved)
389 if (last >= rbl->lastreserved - 4)
390 break;
391 i = rbl->lastreserved & ~(volume.rescluster-1);
394 /* break if nothing found for 128 blocks, and already found promising
395 * candidate. Uses roundrobin allocation
397 if (found && !--found)
398 break;
400 volume.progress(1,1);
401 if (volume.getblock(&blk, i))
402 continue;
404 if (aborting)
406 // break search, don't break repair
407 volume.showmsg("Aborting block search\n");
408 aborting = 0;
409 break;
412 if (blk.data->id == bloktype)
414 if (blk.data->indexblock.seqnr != seqnr && bloktype != EXTENSIONID)
415 continue;
417 if (anodenr && (blk.data->dirblock.anodenr != anodenr ||
418 blk.data->dirblock.parent != parent))
419 continue;
421 if (datestamp && blk.data->dirblock.datestamp > datestamp)
422 continue;
424 /* found block */
425 tmp = (bloktype == EXTENSIONID) ?
426 (blk.data->extensionblock.datestamp) :
427 (blk.data->dirblock.datestamp);
429 if (tmp >= ds)
431 if (datestamp)
433 if (tmp > datestamp)
434 continue;
436 /* found a promising candidate ? */
437 if (datestamp - tmp < 100)
438 found = 512; // 1.3: was 128
440 ds = tmp;
441 bloknr = i;
446 free (blk.data);
447 volume.status(1," ",100);
448 return (uint32)bloknr;
451 /* Get last reserved block */
452 uint32 SearchLastReserved(volume_t *vol)
454 cachedblock_t blk;
455 uint32 i, last, cdwn;
457 blk.data = calloc(1, SIZEOF_RESBLOCK);
458 cdwn = 4096;
459 i = last = vol->disksize/256;
460 i -= i % volume.rescluster;
461 vol->status(1, "Scanning disk", vol->disksize/16 - last);
462 while (i < vol->disksize/16)
464 vol->progress(1,1);
465 if (aborting)
467 volume.showmsg("Aborting filesystem search\n");
468 aborting = 0;
469 break;
472 if (volume.getblock(&blk, i))
473 goto s_ret;
475 switch (blk.data->id)
477 case DBLKID:
478 case ABLKID:
479 case IBLKID:
480 case BMBLKID:
481 case BMIBLKID:
482 case DELDIRID:
483 case EXTENSIONID:
484 case SBLKID:
486 cdwn = 1024;
487 last = i;
488 break;
490 default:
492 /* Exit if blocks not reserved */
493 if (!cdwn--)
494 goto s_ret;
497 i += volume.rescluster;
500 s_ret:
501 free (blk.data);
502 vol->status(1, " ", 100);
503 return last;
506 /* Search filesystem on specified execdevice/unit. Start at startblok,
507 * end at endblok
509 uint32 SearchFileSystem(int32 startblok, int32 endblok)
511 rootblock_t *rbl;
512 uint32 blnr = 0, b;
514 if (!(rbl = (rootblock_t *)AllocBufMem (MAXRESBLOCKSIZE)))
515 return e_out_of_memory;
517 volume.status(0, "Searching filesystem", endblok-startblok);
518 startblok = max(startblok, 0);
519 startblok &= ~1; /* even bloknr */
520 for (b = startblok; b<endblok; b += volume.rescluster)
522 volume.progress(0,1);
523 if (aborting)
525 volume.showmsg("Aborting filesystem search\n");
526 aborting = 0;
527 break;
530 // read block and check if it is a rootblock */
531 if (c_GetBlock ((uint8 *)rbl, b, volume.blocksize))
532 break;
534 if (IsRootBlock(rbl))
536 blnr = b;
537 break;
541 FreeBufMem(rbl);
542 return blnr;
545 /* cached block structure is managed by caller
546 * block data is managed by this function
547 * creates an extension block with uptodate reference to
548 * superblock and no deldir.
550 error_t BuildRext(c_extensionblock_t *rext)
552 struct DateStamp time;
553 struct buildblock *bbl;
554 extensionblock_t *r;
555 scanelement_t ind[16];
556 int i;
558 volume.status(1, "Building rext", (rbl->lastreserved-rbl->firstreserved)/volume.rescluster);
560 if (!(r = rext->data = AllocBufMem(SIZEOF_RESBLOCK)))
561 return e_out_of_memory;
563 if (!(bbl = malloc(sizeof(struct buildblock))))
565 FreeBufMem(r);
566 return e_out_of_memory;
569 memset (r, 0, volume.blocksize);
570 memset (bbl, 0, sizeof(*bbl));
571 DateStamp (&time);
573 r->id = EXTENSIONID;
574 r->datestamp = rbl->datestamp;
575 r->pfs2version = (17<<16) + 99;
576 r->root_date[0] = time.ds_Days;
577 r->root_date[1] = time.ds_Minute;
578 r->root_date[2] = time.ds_Tick;
580 volume.progress(1, 1);
581 if (rbl->options & MODE_SUPERINDEX)
583 memset (ind, 0, 16*sizeof(scanelement_t));
584 SearchBlocks(ind, 0, 15, rbl->firstreserved, rbl->lastreserved, SBLKID);
585 for (i=0; i<16; i++)
586 r->superindex[i] = ind[i].blocknr;
589 /* add to list */
590 bbl->b.blocknr = rext->blocknr = ~0;
591 bbl->b.mode = rext->mode = build;
592 bbl->b.data = (reservedblock_t *)r;
593 MinAddHead(&volume.buildblocks, bbl);
595 volume.status(1, " ", 100);
596 return e_none;
600 /* zet mode to build
602 error_t BuildIndexBlock(c_indexblock_t *blk, uint16 bloktype, uint32 seqnr)
604 struct buildblock *bbl;
605 indexblock_t *ib;
606 int i;
607 uint16 childtype;
608 scanelement_t *ind;
610 volume.status(1, "Building indexblock", INDEX_PER_BLOCK);
611 if (!(ind = calloc(INDEX_PER_BLOCK, sizeof(scanelement_t))))
612 return e_out_of_memory;
614 if (!(ib = blk->data = AllocBufMem(SIZEOF_RESBLOCK))) {
615 free(ind);
616 return e_out_of_memory;
619 if (!(bbl = malloc(sizeof(struct buildblock))))
621 FreeBufMem(ib);
622 free(ind);
623 return e_out_of_memory;
626 memset (ib, 0, volume.blocksize);
627 memset (bbl, 0, sizeof(*bbl));
629 ib->id = bloktype;
630 ib->datestamp = rbl->datestamp;
631 ib->seqnr = seqnr;
633 /* fill index */
634 switch (bloktype)
636 case IBLKID: childtype = ABLKID; break;
637 case BMIBLKID: childtype = BMBLKID; break;
638 case SBLKID: childtype = IBLKID; break;
639 default: return e_fatal_error;
642 SearchBlocks (ind, seqnr*INDEX_PER_BLOCK, seqnr*INDEX_PER_BLOCK + INDEX_PER_BLOCK - 1, rbl->firstreserved, rbl->lastreserved, childtype);
643 for (i=0; i<INDEX_PER_BLOCK; i++)
644 ib->index[i] = ind[i].blocknr;
646 /* add to list */
647 bbl->b.blocknr = blk->blocknr = ~0;
648 bbl->b.mode = blk->mode = build;
649 bbl->b.data = (reservedblock_t *)ib;
650 MinAddHead(&volume.buildblocks, bbl);
652 free(ind);
653 volume.status(1, " ", 100);
654 return e_none;
657 error_t BuildBitmapBlock(c_bitmapblock_t *blk, uint32 seqnr)
659 struct buildblock *bbl;
660 bitmapblock_t *bmb;
661 uint32 *bitmap;
662 int i;
664 volume.status(1, "Building bitmapblock", 100);
665 if (!(bmb = blk->data = AllocBufMem(SIZEOF_RESBLOCK)))
666 return e_out_of_memory;
668 if (!(bbl = malloc(sizeof(struct buildblock))))
670 FreeBufMem(bmb);
671 return e_out_of_memory;
674 memset (bmb, 0, volume.blocksize);
675 memset (bbl, 0, sizeof(*bbl));
677 bmb->id = BMBLKID;
678 bmb->datestamp = rbl->datestamp;
679 bmb->seqnr = seqnr;
681 /* fill bitmap */
682 bitmap = bmb->bitmap;
683 for (i = 0; i<LONGS_PER_BMB; i++)
684 *bitmap++ = ~0;
686 /* add to list */
687 bbl->b.blocknr = blk->blocknr = ~0;
688 bbl->b.mode = blk->mode = build;
689 bbl->b.data = (reservedblock_t *)bmb;
690 MinAddHead(&volume.buildblocks, bbl);
692 volume.status(1, " ", 100);
693 return e_none;