1 #include <devices/scsidisk.h>
2 #include <devices/trackdisk.h>
4 #include <dos/dosextens.h>
5 #include <dos/filehandler.h>
6 #include <exec/errors.h>
8 #include <exec/memory.h>
10 #include <clib-org/exec_protos.h>
14 /* Almost ALL functions in this source are support functions
15 which were quickly copied from the main SFS source. The
16 most interesting function is saveextents(), which performs
17 the actual function of this program. */
20 #include "/fs/bitmap.h"
21 #include "/fs/objects.h"
22 #include "/fs/deviceio.h"
24 #include "/fs/btreenodes.h"
26 #include <devices/newstyle.h> /* Doesn't include exec/types.h which is why it is placed here */
28 #include "/bitfuncs.c"
30 #define BLCKFACCURACY (5) /* 2^5 = 32 */
36 extern ULONG __asm
RANDOM(register __d0 ULONG
);
37 extern LONG __asm
STACKSWAP(void);
38 extern ULONG __asm
CALCCHECKSUM(register __d0 ULONG
,register __a0 ULONG
*);
39 extern ULONG __asm
MULU64(register __d0 ULONG
,register __d1 ULONG
,register __a0 ULONG
*);
40 extern WORD __asm
COMPRESSFROMZERO(register __a0 UWORD
*,register __a1 UBYTE
*,register __d0 ULONG
);
44 LONG
safedoio(UWORD action
,UBYTE
*buffer
,ULONG blocks
,ULONG blockoffset
);
47 struct DosEnvec
*dosenvec
;
49 /* blocks_ = the number of blocks of something (blocks can contain 1 or more sectors)
50 block_ = a block number of something (relative to start of partition)
51 sectors_ = the number of sectors of something (1 or more sectors form a logical block)
52 sector_ = a sector number (relative to the start of the disk)
53 bytes_ = the number of bytes of something
54 byte_ = a byte number of something
55 shifts_ = the number of bytes written as 2^x of something
56 mask_ = a mask for something */
58 ULONG sectors_total
; /* size of the partition in sectors */
59 UWORD sectors_block
; /* number of sectors in a block */
62 ULONG blocks_total
; /* size of the partition in blocks */
63 ULONG blocks_reserved_start
; /* number of blocks reserved at start (=reserved) */
64 ULONG blocks_reserved_end
; /* number of blocks reserved at end (=prealloc) */
65 ULONG blocks_used
; /* number of blocks in use excluding reserved blocks
67 ULONG blocks_bitmap
; /* number of BTMP blocks for this partition */
68 ULONG blocks_inbitmap
; /* number of blocks a single bitmap block can contain info on */
69 ULONG blocks_maxtransfer
=1048576; /* max. blocks which may be transfered to the device at once (limits io_Length) */
71 ULONG block_root
; /* the block offset of the root block */
72 ULONG block_extentbnoderoot
; /* the block offset of the root of the extent bnode tree */
74 ULONG byte_low
; /* the byte offset of our partition on the disk */
75 ULONG byte_lowh
; /* high 32 bits */
76 ULONG byte_high
; /* the byte offset of the end of our partition (excluding) on the disk */
77 ULONG byte_highh
; /* high 32 bits */
79 ULONG bytes_block
; /* size of a block in bytes */
80 ULONG bytes_sector
; /* size of a sector in bytes */
83 ULONG mask_block32
; /* masks the least significant bits of a BLCKf pointer */
84 ULONG mask_mask
=0xFFFFFFFF; /* mask as specified by mountlist */
86 UWORD shifts_block
; /* shift count needed to convert a blockoffset<->byteoffset */
87 UWORD shifts_block32
; /* shift count needed to convert a blockoffset<->32byteoffset (only used by nodes.c!) */
89 ULONG disktype
; /* the type of media inserted (same as id_DiskType in InfoData
91 UBYTE newstyledevice
=FALSE
;
92 UBYTE does64bit
=FALSE
;
93 UBYTE is_casesensitive
=FALSE
;
95 UWORD cmdread
=CMD_READ
;
96 UWORD cmdwrite
=CMD_WRITE
;
99 struct MsgPort
*msgport
;
100 struct IOStdReq
*ioreq
;
103 ULONG block_objectnodesbase
;
104 ULONG block_extentroot
;
112 struct RDArgs
*readarg
;
113 UBYTE
template[]="DEVICE=DRIVE/A\n";
115 struct {char *device
;} arglist
={NULL
};
117 if((DOSBase
=(struct DosLibrary
*)OpenLibrary("dos.library",37))!=0) {
118 if((pool
=CreatePool(0,16384,8192))!=0) {
119 if((readarg
=ReadArgs(template,(LONG
*)&arglist
,0))!=0) {
120 struct MsgPort
*msgport
;
121 struct DeviceNode
*dn
;
122 UBYTE
*devname
=arglist
.device
;
132 dn
=(struct DeviceNode
*)LockDosList(LDF_DEVICES
|LDF_READ
);
133 if((dn
=(struct DeviceNode
*)FindDosEntry((struct DosList
*)dn
,arglist
.device
,LDF_DEVICES
))!=0) {
134 struct FileSysStartupMsg
*fssm
;
136 fssm
=(struct FileSysStartupMsg
*)BADDR(dn
->dn_Startup
);
137 dosenvec
=(struct DosEnvec
*)BADDR(fssm
->fssm_Environ
);
139 UnLockDosList(LDF_DEVICES
|LDF_READ
);
141 if((msgport
=CreateMsgPort())!=0) {
142 if((ioreq
=CreateIORequest(msgport
,sizeof(struct IOStdReq
)))!=0) {
143 if(OpenDevice((UBYTE
*)BADDR(fssm
->fssm_Device
)+1,fssm
->fssm_Unit
,(struct IORequest
*)ioreq
,fssm
->fssm_Flags
)==0) {
145 struct DosEnvec
*de
=dosenvec
;
147 ULONG sectorspercilinder
;
149 bytes_sector
=de
->de_SizeBlock
<<2;
150 bytes_block
=bytes_sector
*de
->de_SectorPerBlock
;
158 shifts_block32
=shifts_block
-BLCKFACCURACY
;
160 mask_block32
=(1<<shifts_block32
)-1;
161 mask_block
=bytes_block
-1;
163 /* Absolute offset on the entire disk are expressed in Sectors;
164 Offset relative to the start of the partition are expressed in Blocks */
166 sectorspercilinder
=de
->de_Surfaces
*de
->de_BlocksPerTrack
; /* 32 bit */
167 sectors_total
=sectorspercilinder
*(de
->de_HighCyl
+1-de
->de_LowCyl
); /* 32 bit */
169 /* sectorspercilinder * bytes_sector cannot exceed 32-bit !! */
171 byte_lowh
= MULU64(sectorspercilinder
* bytes_sector
, de
->de_LowCyl
, &byte_low
);
172 byte_highh
= MULU64(sectorspercilinder
* bytes_sector
, de
->de_HighCyl
+1, &byte_high
);
174 sectors_block
=de
->de_SectorPerBlock
;
176 blocks_total
=sectors_total
/de
->de_SectorPerBlock
;
177 blocks_reserved_start
=de
->de_Reserved
;
178 blocks_reserved_end
=de
->de_PreAlloc
;
180 if(blocks_reserved_start
<1) {
181 blocks_reserved_start
=1;
184 if(blocks_reserved_end
<1) {
185 blocks_reserved_end
=1;
188 blocks_inbitmap
=(bytes_block
-sizeof(struct fsBitmap
))<<3; /* must be a multiple of 32 !! */
189 blocks_bitmap
=(blocks_total
+blocks_inbitmap
-1)/blocks_inbitmap
;
193 printf("Partition start offset : 0x%08lx:%08lx End offset : 0x%08lx:%08lx\n",byte_lowh
,byte_low
,byte_highh
,byte_high
);
194 printf("sectors/block : %ld\n",de
->de_SectorPerBlock
);
195 printf("bytes/sector : %ld\n",bytes_sector
);
196 printf("bytes/block : %ld\n",bytes_block
);
197 printf("Total blocks in partition : %ld\n",blocks_total
);
202 /* If the partition's high byte is beyond the 4 GB border we will
203 try and detect a 64-bit device. */
206 struct NSDeviceQueryResult nsdqr
;
210 /* Checks for newstyle devices and 64-bit support */
212 nsdqr
.SizeAvailable
=0;
213 nsdqr
.DevQueryFormat
=0;
215 ioreq
->io_Command
=NSCMD_DEVICEQUERY
;
216 ioreq
->io_Length
=sizeof(nsdqr
);
217 ioreq
->io_Data
=(APTR
)&nsdqr
;
219 if(DoIO((struct IORequest
*)ioreq
)==0 && (ioreq
->io_Actual
>= 16) && (nsdqr
.SizeAvailable
== ioreq
->io_Actual
) && (nsdqr
.DeviceType
== NSDEVTYPE_TRACKDISK
)) {
220 /* This must be a new style trackdisk device */
224 printf("Device is a new style device (NSD)\n");
226 /* Is it safe to use 64 bits with this driver? We can reject
227 bad mounts pretty easily via this check. */
229 for(cmdcheck
=nsdqr
.SupportedCommands
; *cmdcheck
; cmdcheck
++) {
230 if(*cmdcheck
== NSCMD_TD_READ64
) {
231 /* This trackdisk style device supports the complete 64-bit
232 command set without returning IOERR_NOCMD! */
234 printf("Device supports 64-bit commands\n");
237 cmdread
=NSCMD_TD_READ64
;
238 cmdwrite
=NSCMD_TD_WRITE64
;
243 /* Checks for TD64 supporting devices */
245 ioreq
->io_Command
=24; /* READ64 */
251 errorcode
=DoIO((struct IORequest
*)ioreq
);
252 if(errorcode
!=-1 && errorcode
!=IOERR_NOCMD
) {
253 printf("Device supports 64-bit commands\n");
262 if((buffer
=AllocVec(bytes_block
*2,0))!=0) {
266 printf("Not enough memory\n");
269 CloseDevice((struct IORequest
*)ioreq
);
271 DeleteIORequest(ioreq
);
273 DeleteMsgPort(msgport
);
277 Printf("Unknown device %s\n",arglist
.device
);
278 UnLockDosList(LDF_DEVICES
|LDF_READ
);
285 CloseLibrary((struct Library
*)DOSBase
);
293 else if(SetSignal(0L,SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) {
294 PutStr("\n***Break\n");
300 BOOL
validblock(ULONG block
) {
301 if(block
<blocks_total
) {
311 return(DoIO((struct IORequest
*)ioreq
));
317 LONG
safedoio(UWORD action
,UBYTE
*buffer
,ULONG blocks
,ULONG blockoffset
) {
319 ULONG start
,starthigh
;
323 if(action
==DIO_READ
) {
326 else if(action
==DIO_WRITE
) {
334 start
=(blockoffset
<<shifts_block
)+byte_low
;
335 starthigh
=(blockoffset
>>(32-shifts_block
))+byte_lowh
; /* High offset */
336 if(start
< byte_low
) {
337 starthigh
+=1; /* Add X bit :-) */
340 end
=start
+(blocks
<<shifts_block
);
343 endhigh
+=1; /* Add X bit */
346 ioreq
->io_Data
=buffer
;
347 ioreq
->io_Command
=command
;
348 ioreq
->io_Length
=blocks
<<shifts_block
;
349 ioreq
->io_Offset
=start
;
350 ioreq
->io_Actual
=starthigh
;
352 if( ( starthigh
> byte_lowh
|| (starthigh
== byte_lowh
&& start
>= byte_low
) ) &&
353 ( endhigh
< byte_highh
|| (endhigh
== byte_highh
&& end
<= byte_high
) ) ) {
355 /* We're about to do a physical disk access. (Re)set timeout. Since
356 the drive's motor will be turned off with the timeout as well we
357 always (re)set the timeout even if doio() would return an error. */
359 if((errorcode
=doio())!=0) {
364 // DEBUG(("byte_low = 0x%08lx:%08lx, byte_high = 0x%08lx:%08lx\n",byte_lowh,byte_low,byte_highh,byte_high));
365 // DEBUG(("start = 0x%08lx:%08lx, end = 0x%08lx:%08lx\n",starthigh,start,endhigh,end));
367 return(INTERR_OUTSIDE_PARTITION
);
376 BOOL
checkchecksum(void *d
) {
377 ULONG
*data
=(ULONG
*)d
;
379 if(CALCCHECKSUM(bytes_block
,data
)==0) {
387 struct fsObject
*nextobject(struct fsObject
*o
) {
390 /* skips the passed in fsObject and gives a pointer back to the place where
391 a next fsObject structure could be located */
393 p
=(UBYTE
*)&o
->name
[0];
395 /* skip the filename */
399 /* skip the comment */
403 /* ensure WORD boundary */
404 if((((ULONG
)p
) & 0x01)!=0) {
408 return((struct fsObject
*)p
);
413 WORD
isobject(struct fsObject
*o
, struct fsObjectContainer
*oc
) {
416 endadr
=(UBYTE
*)oc
+bytes_block
-sizeof(struct fsObject
)-2;
418 if((UBYTE
*)o
<endadr
&& o
->name
[0]!=0) {
426 LONG
read(ULONG block
) {
427 return(safedoio(DIO_READ
, buffer
, 1, block
));
432 struct BNode
*searchforbnode(ULONG key
, struct BTreeContainer
*tc
) {
434 WORD n
=tc
->nodecount
-1;
436 tn
=(struct BNode
*)((UBYTE
*)tc
->bnode
+n
*tc
->nodesize
);
439 if(n
<=0 || key
>= tn
->key
) {
442 tn
=(struct BNode
*)((UBYTE
*)tn
-tc
->nodesize
);
449 LONG
findbnode(BLCK rootblock
,ULONG key
,struct BNode
**returned_bnode
) {
452 while((errorcode
=read(rootblock
))==0) {
453 struct fsBNodeContainer
*bnc
=(struct fsBNodeContainer
*)buffer
;
454 struct BTreeContainer
*btc
=&bnc
->btc
;
456 if(btc
->nodecount
==0) {
461 *returned_bnode
=searchforbnode(key
,btc
);
462 if(btc
->isleaf
==TRUE
) {
465 rootblock
=(*returned_bnode
)->data
;
474 struct fsExtentBNode
*ebn
;
475 LONG n
=blocks_bitmap
;
476 ULONG bitmapblock
=34;
480 while(n
-->0 && (errorcode
=read(bitmapblock
))==0) {
481 struct fsBitmap
*b
=(struct fsBitmap
*)(buffer
+bytes_block
);
483 CopyMemQuick(buffer
, b
, bytes_block
);
486 if(block
>=blocks_total
) {
490 if((block
/ blocks_inbitmap
)!=bitmapblock
-34) {
494 if((errorcode
=findbnode(6, block
, (struct BNode
**)&ebn
))!=0) {
495 printf("Error %ld occured during scanning (findbnode).\n",errorcode
);
500 if(ebn
==0 || ebn
->key
!=block
) {
501 ULONG offset
=(block
% blocks_inbitmap
);
503 if((b
->bitmap
[offset
/32] & (1<<(31-(offset
& 0x1F))))==0) {
512 UWORD blocks
=ebn
->blocks
;
518 if((ebn
->prev
& 0x80000000)==0) {
549 printf("Error %ld occured during scanning.\n",errorcode
);