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 findobjects(), which performs
17 the actual function of this program. */
20 #include "/fs/objects.h"
21 #include "/fs/deviceio.h"
23 #include "/fs/btreenodes.h"
25 #include <devices/newstyle.h> /* Doesn't include exec/types.h which is why it is placed here */
27 #include "/fs/bitfuncs.c"
29 #define BLCKFACCURACY (5) /* 2^5 = 32 */
35 extern ULONG __asm
RANDOM(register __d0 ULONG
);
36 extern LONG __asm
STACKSWAP(void);
37 extern ULONG __asm
CALCCHECKSUM(register __d0 ULONG
,register __a0 ULONG
*);
38 extern ULONG __asm
MULU64(register __d0 ULONG
,register __d1 ULONG
,register __a0 ULONG
*);
39 extern WORD __asm
COMPRESSFROMZERO(register __a0 UWORD
*,register __a1 UBYTE
*,register __d0 ULONG
);
43 LONG
safedoio(UWORD action
,UBYTE
*buffer
,ULONG blocks
,ULONG blockoffset
);
44 void findobjects(UBYTE
*pattern
);
46 struct DosEnvec
*dosenvec
;
48 /* blocks_ = the number of blocks of something (blocks can contain 1 or more sectors)
49 block_ = a block number of something (relative to start of partition)
50 sectors_ = the number of sectors of something (1 or more sectors form a logical block)
51 sector_ = a sector number (relative to the start of the disk)
52 bytes_ = the number of bytes of something
53 byte_ = a byte number of something
54 shifts_ = the number of bytes written as 2^x of something
55 mask_ = a mask for something */
57 ULONG sectors_total
; /* size of the partition in sectors */
58 UWORD sectors_block
; /* number of sectors in a block */
61 ULONG blocks_total
; /* size of the partition in blocks */
62 ULONG blocks_reserved_start
; /* number of blocks reserved at start (=reserved) */
63 ULONG blocks_reserved_end
; /* number of blocks reserved at end (=prealloc) */
64 ULONG blocks_used
; /* number of blocks in use excluding reserved blocks
66 ULONG blocks_maxtransfer
=1048576; /* max. blocks which may be transfered to the device at once (limits io_Length) */
68 ULONG block_root
; /* the block offset of the root block */
69 ULONG block_extentbnoderoot
; /* the block offset of the root of the extent bnode tree */
71 ULONG byte_low
; /* the byte offset of our partition on the disk */
72 ULONG byte_lowh
; /* high 32 bits */
73 ULONG byte_high
; /* the byte offset of the end of our partition (excluding) on the disk */
74 ULONG byte_highh
; /* high 32 bits */
76 ULONG bytes_block
; /* size of a block in bytes */
77 ULONG bytes_sector
; /* size of a sector in bytes */
80 ULONG mask_block32
; /* masks the least significant bits of a BLCKf pointer */
81 ULONG mask_mask
=0xFFFFFFFF; /* mask as specified by mountlist */
84 UWORD shifts_block
; /* shift count needed to convert a blockoffset<->byteoffset */
85 UWORD shifts_block32
; /* shift count needed to convert a blockoffset<->32byteoffset (only used by nodes.c!) */
87 ULONG disktype
; /* the type of media inserted (same as id_DiskType in InfoData
89 UBYTE newstyledevice
=FALSE
;
90 UBYTE does64bit
=FALSE
;
91 UBYTE is_casesensitive
=FALSE
;
93 UWORD cmdread
=CMD_READ
;
94 UWORD cmdwrite
=CMD_WRITE
;
97 struct MsgPort
*msgport
;
98 struct IOStdReq
*ioreq
;
101 ULONG block_objectnodesbase
;
102 ULONG block_extentroot
;
110 struct RDArgs
*readarg
;
111 UBYTE
template[]="DEVICE=DRIVE/A,NAMEPATTERN/A\n";
113 struct {char *device
;
114 char *name
;} arglist
={NULL
};
116 if((DOSBase
=(struct DosLibrary
*)OpenLibrary("dos.library",37))!=0) {
117 if((pool
=CreatePool(0,16384,8192))!=0) {
118 if((readarg
=ReadArgs(template,(LONG
*)&arglist
,0))!=0) {
119 struct MsgPort
*msgport
;
120 struct DeviceNode
*dn
;
121 UBYTE
*devname
=arglist
.device
;
131 dn
=(struct DeviceNode
*)LockDosList(LDF_DEVICES
|LDF_READ
);
132 if((dn
=(struct DeviceNode
*)FindDosEntry((struct DosList
*)dn
,arglist
.device
,LDF_DEVICES
))!=0) {
133 struct FileSysStartupMsg
*fssm
;
135 fssm
=(struct FileSysStartupMsg
*)BADDR(dn
->dn_Startup
);
136 dosenvec
=(struct DosEnvec
*)BADDR(fssm
->fssm_Environ
);
138 UnLockDosList(LDF_DEVICES
|LDF_READ
);
140 if((msgport
=CreateMsgPort())!=0) {
141 if((ioreq
=CreateIORequest(msgport
,sizeof(struct IOStdReq
)))!=0) {
142 if(OpenDevice((UBYTE
*)BADDR(fssm
->fssm_Device
)+1,fssm
->fssm_Unit
,(struct IORequest
*)ioreq
,fssm
->fssm_Flags
)==0) {
144 struct DosEnvec
*de
=dosenvec
;
146 ULONG sectorspercilinder
;
148 bytes_sector
=de
->de_SizeBlock
<<2;
149 bytes_block
=bytes_sector
*de
->de_SectorPerBlock
;
157 shifts_block32
=shifts_block
-BLCKFACCURACY
;
159 mask_block32
=(1<<shifts_block32
)-1;
160 mask_block
=bytes_block
-1;
162 /* Absolute offset on the entire disk are expressed in Sectors;
163 Offset relative to the start of the partition are expressed in Blocks */
165 sectorspercilinder
=de
->de_Surfaces
*de
->de_BlocksPerTrack
; /* 32 bit */
166 sectors_total
=sectorspercilinder
*(de
->de_HighCyl
+1-de
->de_LowCyl
); /* 32 bit */
168 /* sectorspercilinder * bytes_sector cannot exceed 32-bit !! */
170 byte_lowh
= MULU64(sectorspercilinder
* bytes_sector
, de
->de_LowCyl
, &byte_low
);
171 byte_highh
= MULU64(sectorspercilinder
* bytes_sector
, de
->de_HighCyl
+1, &byte_high
);
173 sectors_block
=de
->de_SectorPerBlock
;
175 blocks_total
=sectors_total
/de
->de_SectorPerBlock
;
176 blocks_reserved_start
=de
->de_Reserved
;
177 blocks_reserved_end
=de
->de_PreAlloc
;
179 if(blocks_reserved_start
<1) {
180 blocks_reserved_start
=1;
183 if(blocks_reserved_end
<1) {
184 blocks_reserved_end
=1;
189 printf("Partition start offset : 0x%08lx:%08lx End offset : 0x%08lx:%08lx\n",byte_lowh
,byte_low
,byte_highh
,byte_high
);
190 printf("sectors/block : %ld\n",de
->de_SectorPerBlock
);
191 printf("bytes/sector : %ld\n",bytes_sector
);
192 printf("bytes/block : %ld\n",bytes_block
);
193 printf("Total blocks in partition : %ld\n",blocks_total
);
198 /* If the partition's high byte is beyond the 4 GB border we will
199 try and detect a 64-bit device. */
202 struct NSDeviceQueryResult nsdqr
;
206 /* Checks for newstyle devices and 64-bit support */
208 nsdqr
.SizeAvailable
=0;
209 nsdqr
.DevQueryFormat
=0;
211 ioreq
->io_Command
=NSCMD_DEVICEQUERY
;
212 ioreq
->io_Length
=sizeof(nsdqr
);
213 ioreq
->io_Data
=(APTR
)&nsdqr
;
215 if(DoIO((struct IORequest
*)ioreq
)==0 && (ioreq
->io_Actual
>= 16) && (nsdqr
.SizeAvailable
== ioreq
->io_Actual
) && (nsdqr
.DeviceType
== NSDEVTYPE_TRACKDISK
)) {
216 /* This must be a new style trackdisk device */
220 printf("Device is a new style device (NSD)\n");
222 /* Is it safe to use 64 bits with this driver? We can reject
223 bad mounts pretty easily via this check. */
225 for(cmdcheck
=nsdqr
.SupportedCommands
; *cmdcheck
; cmdcheck
++) {
226 if(*cmdcheck
== NSCMD_TD_READ64
) {
227 /* This trackdisk style device supports the complete 64-bit
228 command set without returning IOERR_NOCMD! */
230 printf("Device supports 64-bit commands\n");
233 cmdread
=NSCMD_TD_READ64
;
234 cmdwrite
=NSCMD_TD_WRITE64
;
239 /* Checks for TD64 supporting devices */
241 ioreq
->io_Command
=24; /* READ64 */
247 errorcode
=DoIO((struct IORequest
*)ioreq
);
248 if(errorcode
!=-1 && errorcode
!=IOERR_NOCMD
) {
249 printf("Device supports 64-bit commands\n");
258 if((buffer
=AllocVec(bytes_block
,0))!=0) {
259 findobjects(arglist
.name
);
262 printf("Not enough memory\n");
265 CloseDevice((struct IORequest
*)ioreq
);
267 DeleteIORequest(ioreq
);
269 DeleteMsgPort(msgport
);
273 VPrintf("Unknown device %s\n",&arglist
.device
);
274 UnLockDosList(LDF_DEVICES
|LDF_READ
);
281 CloseLibrary((struct Library
*)DOSBase
);
289 else if(SetSignal(0L,SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) {
290 PutStr("\n***Break\n");
296 BOOL
validblock(ULONG block
) {
297 if(block
<blocks_total
) {
309 return(DoIO((struct IORequest
*)ioreq
));
312 while((errorcode=DoIO((struct IORequest *)ioreq))!=0) {
313 if(errorcode==TDERR_WriteProt) {
314 if(request(PROGRAMNAME " request","%s\n"\
315 "is write protected.\n",
316 "Retry|Cancel",((UBYTE *)BADDR(devnode->dn_Name))+1)<=0) {
320 else if(errorcode==TDERR_DiskChanged) {
321 if(request(PROGRAMNAME " request","You MUST insert volume %s\n"\
322 "There still was some data which needs to be transfered!\n",
323 "Retry|Cancel",((UBYTE *)BADDR(devnode->dn_Name))+1)<=0) {
328 if(request(PROGRAMNAME " request","%s\n"\
329 "returned an error while volume %s was accessing it.\n\n"\
331 "io_Command = %ld\n"\
335 "Retry|Cancel",(UBYTE *)BADDR(startupmsg->fssm_Device)+1,((UBYTE *)BADDR(devnode->dn_Name))+1,errorcode,(ULONG)ioreq->io_Command,ioreq->io_Offset,ioreq->io_Length,ioreq->io_Actual)<=0) {
346 LONG
safedoio(UWORD action
,UBYTE
*buffer
,ULONG blocks
,ULONG blockoffset
) {
348 ULONG start
,starthigh
;
352 if(action
==DIO_READ
) {
355 else if(action
==DIO_WRITE
) {
363 start
=(blockoffset
<<shifts_block
)+byte_low
;
364 starthigh
=(blockoffset
>>(32-shifts_block
))+byte_lowh
; /* High offset */
365 if(start
< byte_low
) {
366 starthigh
+=1; /* Add X bit :-) */
369 end
=start
+(blocks
<<shifts_block
);
372 endhigh
+=1; /* Add X bit */
375 ioreq
->io_Data
=buffer
;
376 ioreq
->io_Command
=command
;
377 ioreq
->io_Length
=blocks
<<shifts_block
;
378 ioreq
->io_Offset
=start
;
379 ioreq
->io_Actual
=starthigh
;
381 if( ( starthigh
> byte_lowh
|| (starthigh
== byte_lowh
&& start
>= byte_low
) ) &&
382 ( endhigh
< byte_highh
|| (endhigh
== byte_highh
&& end
<= byte_high
) ) ) {
384 /* We're about to do a physical disk access. (Re)set timeout. Since
385 the drive's motor will be turned off with the timeout as well we
386 always (re)set the timeout even if doio() would return an error. */
388 if((errorcode
=doio())!=0) {
393 // DEBUG(("byte_low = 0x%08lx:%08lx, byte_high = 0x%08lx:%08lx\n",byte_lowh,byte_low,byte_highh,byte_high));
394 // DEBUG(("start = 0x%08lx:%08lx, end = 0x%08lx:%08lx\n",starthigh,start,endhigh,end));
396 return(INTERR_OUTSIDE_PARTITION
);
405 BOOL
checkchecksum(void *d
) {
406 ULONG
*data
=(ULONG
*)d
;
408 if(CALCCHECKSUM(bytes_block
,data
)==0) {
416 struct fsObject
*nextobject(struct fsObject
*o
) {
419 /* skips the passed in fsObject and gives a pointer back to the place where
420 a next fsObject structure could be located */
422 p
=(UBYTE
*)&o
->name
[0];
424 /* skip the filename */
428 /* skip the comment */
432 /* ensure WORD boundary */
433 if((((ULONG
)p
) & 0x01)!=0) {
437 return((struct fsObject
*)p
);
442 WORD
isobject(struct fsObject
*o
, struct fsObjectContainer
*oc
) {
445 endadr
=(UBYTE
*)oc
+bytes_block
-sizeof(struct fsObject
)-2;
447 if((UBYTE
*)o
<endadr
&& o
->name
[0]!=0) {
455 LONG findnode(BLCK nodeindex,UWORD nodesize,NODE nodeno,struct fsNode **returned_node) {
458 /* Finds a specific node by number. It returns the cachebuffer which contains the fsNode
459 structure and a pointer to the fsNode structure directly. */
461 while((errorcode
=read(nodeindex
))==0) {
462 struct fsNodeContainer
*nc
=(struct fsNodeContainer
*)buffer
;
465 /* We've descended the tree to a leaf NodeContainer */
467 *returned_node
=(struct fsNode
*)((UBYTE
*)nc
->node
+nodesize
*(nodeno
-nc
->nodenumber
));
472 UWORD containerentry
=(nodeno
-nc
->nodenumber
)/nc
->nodes
;
474 nodeindex
=nc
->node
[containerentry
]>>shifts_block32
;
483 void datetodatestamp(ULONG date
, struct DateStamp
*datestamp
) {
486 datestamp
->ds_Days
= date
/86400;
488 seconds
=date
- (datestamp
->ds_Days
* 86400);
490 datestamp
->ds_Minute
= (ULONG
)((UWORD
)(seconds
/60));
491 datestamp
->ds_Tick
= (ULONG
)((UWORD
)(seconds
%60)*50);
496 void findobjects(UBYTE
*pattern
) {
503 if((ParsePatternNoCase(pattern
, dest
, 510))!=-1) {
507 stepsize
=131072/bytes_block
;
509 if((buf
=AllocVec(131072,0))!=0) {
513 for(n
=0; n
<blocks_total
; n
+=stepsize
) {
514 blockstoread
=stepsize
;
516 if(n
+blockstoread
> blocks_total
) {
517 blockstoread
=blocks_total
-n
;
520 if((errorcode
=safedoio(DIO_READ
, buf
, blockstoread
, n
))==0) {
521 struct fsBlockHeader
*bh
;
524 for(m
=0; m
<blockstoread
; m
++) {
525 bh
=(struct fsBlockHeader
*)(buf
+(m
<<shifts_block
));
527 if(bh
->id
==OBJECTCONTAINER_ID
&& bh
->ownblock
==n
+m
&& checkchecksum(bh
)) {
528 struct fsObjectContainer
*oc
=(struct fsObjectContainer
*)bh
;
529 struct fsObject
*o
=oc
->object
;
531 /* It looks like a valid ObjectContainer block. Let's see if there
532 is a file in there which we are looking for. */
534 while(isobject(o
,oc
)!=FALSE
) {
535 datetodatestamp(o
->datemodified
, &dt
.dat_Stamp
);
537 dt
.dat_Format
=FORMAT_DOS
;
545 if((o
->bits
& OTYPE_DIR
)==0) {
546 if((MatchPatternNoCase(dest
, o
->name
))!=0) {
547 printf("Found file '%s' (%ld bytes, %s %s) in block %ld. ObjectNode %ld, FirstDataBlock %ld.\n", o
->name
, o
->object
.file
.size
, date
, time
, n
+m
, o
->objectnode
, o
->object
.file
.data
);
556 PrintFault(errorcode
, "Error while reading data");
563 printf("Couldn't allocate memory for read buffer\n");
567 PrintFault(IoErr(), "Couldn't parse pattern");