3 * Revision 2.5 1999/09/10 22:14:49 Michiel
6 * Revision 2.4 1999/05/07 16:49:00 Michiel
9 * Revision 2.3 1999/05/04 17:59:09 Michiel
10 * check mode, logfile, search rootblock implemented
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
29 #include <proto/exec.h>
30 #include <proto/dos.h>
31 #include <clib/alib_protos.h>
35 uint32 maxdatestamp
= 0;
37 void InitFullScan(void)
39 NewList((struct List
*)&volume
.buildblocks
);
43 void ExitFullScan(void)
45 buildblock_t
*bbl
, *next
;
47 for (bbl
= HeadOf(&volume
.buildblocks
); (next
=bbl
->next
); bbl
=next
)
50 FreeBufMem(bbl
->b
.data
);
55 /* Allocate create blocks. Write them to the cache and free
57 * pre: resbitmap ready and valid
59 error_t
AllocBuildBlocks(void)
61 buildblock_t
*bbl
, *next
;
63 error_t error
= e_none
;
64 uint32 blocknr
, offset
, seqnr
;
67 for (bbl
= HeadOf(&volume
.buildblocks
); bbl
->next
; bbl
=next
)
69 volume
.progress(0, 1);
71 blocknr
= fs_AllocResBlock();
74 bbl
->b
.blocknr
= blocknr
;
76 volume
.writeblock(&bbl
->b
);
77 switch(bbl
->b
.data
->id
)
80 rbl
->extension
= blocknr
;
81 c_WriteBlock((uint8
*)rbl
, ROOTBLOCK
+ volume
.firstblock
, volume
.blocksize
);
83 rext
.data
= calloc(1, SIZEOF_RESBLOCK
);
84 rext
.blocknr
= blocknr
;
85 memcpy(rext
.data
, bbl
->b
.data
, SIZEOF_RESBLOCK
);
89 rext
.data
->superindex
[bbl
->b
.data
->indexblock
.seqnr
] = blocknr
;
90 volume
.writeblock((cachedblock_t
*)&rext
);
94 rbl
->idx
.large
.bitmapindex
[bbl
->b
.data
->indexblock
.seqnr
] = blocknr
;
95 c_WriteBlock((uint8
*)rbl
, ROOTBLOCK
+ volume
.firstblock
, volume
.blocksize
);
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
);
108 if (bbl
->b
.data
->id
== BMBLKID
)
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
);
116 GetResBlock(&tblk
, type
, seqnr
, true);
117 tblk
.data
->indexblock
.index
[offset
] = blocknr
;
118 volume
.writeblock(&tblk
);
123 adderror("memory allocation error");
124 return e_out_of_memory
;
130 FreeBufMem(bbl
->b
.data
);
135 adderror("allocation error");
136 error
= e_alloc_fail
;
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
;
151 for (i
=0; i
<volume
.resbitmap
->lwsize
; i
++)
153 field
= volume
.resbitmap
->map
[i
];
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
);
171 /* reserved area full */
175 /* Redefine volume from rootblock located at 'bloknr'
177 error_t
Repartition(uint32 bloknr
)
180 error_t error
= e_none
;
182 if (!(rbl
= (rootblock_t
*)AllocBufMem (MAXRESBLOCKSIZE
)))
183 return e_out_of_memory
;
186 error
= c_GetBlock ((uint8
*)rbl
, ROOTBLOCK
+ volume
.firstblock
, volume
.blocksize
);
190 if (!IsRootBlock(rbl
) || !rbl
->disksize
)
192 error
= e_syntax_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;
208 /* special case: no alloc needed */
209 error_t
BuildBootBlock(void)
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
);
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
;
232 scanelement_t ind
[104];
233 uint32 resblocksize
= 1024;
235 volume
.status(0, "Building rootblock", 3);
236 memset (rbl
, 0, volume
.blocksize
);
239 rbl
->disktype
= ID_PFS_DISK
;
240 rbl
->options
= MODE_HARDDISK
| MODE_SPLITTED_ANODES
| MODE_DIR_EXTENSION
|
241 MODE_SIZEFIELD
| MODE_DATESTAMP
| MODE_EXTROVING
;
243 rbl
->options
|= MODE_LARGEFILE
;
244 rbl
->disktype
= ID_PFS2_DISK
;
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
;
253 if (volume
.disksize
> MAXDISKSIZE2K
)
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
)
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
);
297 rbl
->idx
.small
.indexblocks
[i
] = ind
[i
].blocknr
;
299 rbl
->datestamp
= maxdatestamp
+ 0x200;
300 volume
.progress(0,1);
301 volume
.status(1, " ", 100);
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
)
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
))
328 volume
.showmsg("Aborting block search\n");
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
);
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
359 * bloktypes: REXT, BM, BMI, S, AI, A, D
361 uint32
SearchBlock(uint16 bloktype
, uint32 seqnr
, uint32 last
, uint32 datestamp
, uint32 anodenr
,
366 int32 i
, bloknr
; // signed !!
369 blk
.data
= calloc(1, SIZEOF_RESBLOCK
);
374 last
= min(rbl
->lastreserved
, last
);
377 last
= rbl
->lastreserved
;
378 last
-= (last
% volume
.rescluster
);
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)
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
)
400 volume
.progress(1,1);
401 if (volume
.getblock(&blk
, i
))
406 // break search, don't break repair
407 volume
.showmsg("Aborting block search\n");
412 if (blk
.data
->id
== bloktype
)
414 if (blk
.data
->indexblock
.seqnr
!= seqnr
&& bloktype
!= EXTENSIONID
)
417 if (anodenr
&& (blk
.data
->dirblock
.anodenr
!= anodenr
||
418 blk
.data
->dirblock
.parent
!= parent
))
421 if (datestamp
&& blk
.data
->dirblock
.datestamp
> datestamp
)
425 tmp
= (bloktype
== EXTENSIONID
) ?
426 (blk
.data
->extensionblock
.datestamp
) :
427 (blk
.data
->dirblock
.datestamp
);
436 /* found a promising candidate ? */
437 if (datestamp
- tmp
< 100)
438 found
= 512; // 1.3: was 128
447 volume
.status(1," ",100);
448 return (uint32
)bloknr
;
451 /* Get last reserved block */
452 uint32
SearchLastReserved(volume_t
*vol
)
455 uint32 i
, last
, cdwn
;
457 blk
.data
= calloc(1, SIZEOF_RESBLOCK
);
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)
467 volume
.showmsg("Aborting filesystem search\n");
472 if (volume
.getblock(&blk
, i
))
475 switch (blk
.data
->id
)
492 /* Exit if blocks not reserved */
497 i
+= volume
.rescluster
;
502 vol
->status(1, " ", 100);
506 /* Search filesystem on specified execdevice/unit. Start at startblok,
509 uint32
SearchFileSystem(int32 startblok
, int32 endblok
)
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);
525 volume
.showmsg("Aborting filesystem search\n");
530 // read block and check if it is a rootblock */
531 if (c_GetBlock ((uint8
*)rbl
, b
, volume
.blocksize
))
534 if (IsRootBlock(rbl
))
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
;
555 scanelement_t ind
[16];
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
))))
566 return e_out_of_memory
;
569 memset (r
, 0, volume
.blocksize
);
570 memset (bbl
, 0, sizeof(*bbl
));
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
);
586 r
->superindex
[i
] = ind
[i
].blocknr
;
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);
602 error_t
BuildIndexBlock(c_indexblock_t
*blk
, uint16 bloktype
, uint32 seqnr
)
604 struct buildblock
*bbl
;
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
))) {
616 return e_out_of_memory
;
619 if (!(bbl
= malloc(sizeof(struct buildblock
))))
623 return e_out_of_memory
;
626 memset (ib
, 0, volume
.blocksize
);
627 memset (bbl
, 0, sizeof(*bbl
));
630 ib
->datestamp
= rbl
->datestamp
;
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
;
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
);
653 volume
.status(1, " ", 100);
657 error_t
BuildBitmapBlock(c_bitmapblock_t
*blk
, uint32 seqnr
)
659 struct buildblock
*bbl
;
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
))))
671 return e_out_of_memory
;
674 memset (bmb
, 0, volume
.blocksize
);
675 memset (bbl
, 0, sizeof(*bbl
));
678 bmb
->datestamp
= rbl
->datestamp
;
682 bitmap
= bmb
->bitmap
;
683 for (i
= 0; i
<LONGS_PER_BMB
; i
++)
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);