/* undelete.c - undelete files-11 files - RSX, DECUS C, FILES-11 level 1.1 */
/* after find.c */
/* based on fid.c */
/* based on bum.c */
/* understands all flavours of wildcards */
/* breaks if not ODS-1 : it assumes lots of default offsets */

#include <stdio.h>
#include <cx.h>
#include <qioret.h>
#include <f11.h>
#include <f11mor.h>
#include <nboff.h>
#include <fdoff.h>
#include <algol68.h>

struct	home	homblk;		/* home block				*/
struct	header	hedblk;		/* file header				*/
struct	bithead	bhead;		/* bitmap header			*/
char	bitblk[512];		/* bitmap block				*/
char	indxnm[100];		/* index file print name		*/

FILE *	indexf;			/* [0,0]indexf.sys;1			*/
FILE *	bitmapf;		/* [0,0]bitmap.sys;1			*/
unsigned	filnum;		/* file number				*/
unsigned	filoff;		/* (VBN of header (1,1) in indexf.sys)-1*/
unsigned	maxfil;		/* maximum file number (permitted by	*/
				/* bitmap of index file)		*/
FDB *	fdbp;			/* point to fdb of indexf for fcs rape	*/

char	nam[10];		/* file name from this header		*/
char	ext[4];			/* file extension from this header	*/
int	proj;			/* project number from this header	*/
int	prog;			/* programmer number from this header	*/
int	ver;			/* version number from this header	*/

char	wnam[10];		/* the name user is looking for		*/
char	wext[4];		/* the extension user wants		*/
				/* a % in above means match anything	*/
				/* one day we will implement -		*/
int	wproj;			/* the group # user wants		*/
int	wprog;			/* the user # user wants		*/
int	wver;			/* the version user wants		*/
				/* a -1 in above means wild		*/
				/* one day we will mask bits, and range	*/
char	wdev[10];		/* user nominated device		*/

main(argc,argv)
int	argc;
char ** argv;
BEGIN
char *	p;
BOOL	accept;

	IF	(argc!=2)
	THEN	printf("usage: %s [device_name:]filespec [-r]\n",argv[0]);
		printf("the filespec may be as wild as [*,*]mum%%%ble.*;*\n");
		printf("each recoverable file, asks you which filename you want to give it\n");
		printf("if you reply with an empty name, file is not recovered");
		exit();
	FI;
	$_$uc(argv[1]);		/* uppercase everything */
	IF	(p=strchr(argv[1],':'))
	THEN	p++;
		copy(wdev,argv[1],p-argv[1]);
	ELSE	p = argv[1];
		strcpy(wdev,"");
	FI
	/* p just after ':', wdev known */
	IF	(*p=='[')
	THEN	p++;
		IF	(*p=='*' || *p==',')
		THEN	wproj = -1;
			IF	(*p!=',')
			THEN	p++;
			FI
		ELSE	wproj=0;
			WHILE	(isoctal(*p))
			DO	wproj = wproj*8 + (*p++)-'0';
			OD
		FI
		/* p points to ',' and wproj is known */
		IF	(*p++!=',')
		THEN	error("\7can't see ',' in []");
		FI
		IF	(*p=='*' || *p==']')
		THEN	wprog = -1;
			IF	(*p!=']')
			THEN	p++;
			FI
		ELSE	wprog=0;
			WHILE	(isoctal(*p))
			DO	wprog = wprog*8 + (*p++)-'0';
			OD
		FI
		/* *p -> '[' and wprog is known */
		IF	(*p++!=']')
		THEN	error("\7can't see ']' in []");
		FI
	ELSE	wproj = wprog = -1;
	FI
	/* p points to filename.    wproj,wprog known */
	strcpy(wnam,"%%%%%%%%%");
	strcpy(wext,"%%%");
	constr(wnam,'.',&p);
	IF	(*p=='.')
	THEN	p++;
		constr(wext,';',&p);
	FI
	IF	(*p==';')
	THEN	p++;
		FOR	(wver=0;	isoctal(*p);	p++)
		DO	wver = wver*8 + *p-'0';
		OD
	FI
	IF	(*p)
	THEN	fprintf(stderr,"%s: rest of ambiguous file spec ignored: \"%s\"\n\7"
			,argv[0],p);
	FI
	strcpy(indxnm,wdev);
	strcat(indxnm,"[0,0]indexf.sys;1");
	IF	(! (indexf=fopenr(indxnm,512)) )
	THEN	error("\7$$ferr=%oo fopenr: %s",$$ferr,indxnm);
	FI
	/* now fake end-of-file to fcs: so we can read home block */
	fdbp = indexf -> io_fdb;
	fdbp -> f_fatt . f_hibk = fdbp -> f_fatt . f_efbk = 42;
	IF	(frget(&homblk,512,indexf,2L))
	THEN	error("\7$$ferr=%oo home",$$ferr);
	FI
	filoff = 2 + homblk . h_ibsz;
	maxfil = homblk . h_fmax;
	fdbp -> f_fatt . f_hibk = fdbp -> f_fatt . f_efbk = maxfil + 1;
	/* re-use of fdbp OK now */
	strcpy(bitmnm,wdev);
	strcat(bitmnm,"[0,0]bitmap.sys;1");
	IF	(! (bitmapf=fopenr(bitmnm,512)) )
	THEN	error("$$ferr=%Oo fopenr: %s",$$ferr,bitmnm);
	FI
	/* fake eof to fcs: so we can read it */
	fdbp = bitmapf -> io_fdb;
	fdbp -> f_fatt . f_hibk = fdbp -> f_fatt . f_efblk = 2;
	IF	(frget(&bhead,512,bitmapf,1L))
	THEN	error("\7$$ferr=%oo bitmaphead",$$ferr);
	FI
	fdbp -> f_fatt . f_hibk = fdbp -> f_fatt . f_efbk = bhead.bh_nbb + 2;
	/* we can now read (&write?) whole bitmap file */
	/* re-use of fdbp OK now */

	FOR	(filnum=1;	filnum<maxfil+1;	filnum++)
	DO	IF	(frget(&hedblk,512,indexf,(long)(filnum+filoff)))
		THEN	error("$$ferr=%oo header read",$$ferr);
		ELSE	r50toa(nam,&hedblk.i_fnam,3);
			nam[9] = EOS;
			r50toa(ext,&hedblk.i_ftyp,1);
			ext[3] = EOS;
			proj = hedblk.h_proj & 0xFF;
			prog = hedblk.h_prog & 0xFF;
			accept = TRUE;
			IF	(wproj>=0 && wproj!=proj)
			THEN	accept = FALSE;
			FI
			IF	(wprog>=0 && wprog!=prog)
			THEN	accept = FALSE;
			FI
			IF	(compare(ext,wext,3))
			THEN	accept = FALSE;
			FI
			IF	(compare(nam,wnam,9))
			THEN	accept = FALSE;
			FI
			IF	(accept)
			THEN	printf("[%o,%o]%s.%s;%o\\%d. (%o:%o)\n"
				,hedblk.h_proj&0xFF,hedblk.h_prog&0xFF,nam,ext
				,hedblk.i_fver,hedblk.i_rvno,hedblk.h_fnum
				,hedblk.h_fseq);
				recover();
			FI
		FI
	OD
END

/*
 * recover()
 *
 * in:	hedblk	holds 0th file header for this file
 * do:		display header details to user:
 *			each inconsistent index file bitmap bit
 *			each re-used disk bitmap bit
 * out:		if user requests, then:
 *			recover each header
 *			mark each index bitmap bit as used
 *			mark each disk bitmap as used
 */
recover()
BEGIN
long	ivbn;		/* vbn of this index block */
int	esn;		/* extension segment number of this index block */
	esn = 0;
	ivbn = hedblk.m_efnu;
???

END

xwfree(vbn)		/* gripe if index file bitmap says vbn is used */
long	vbn;
BEGIN
int	bytndx;
int	msk;
long	blk;
int	bitnum;
	blk = vbn>>12;
	bitnum = vbn & 0xFFFF;
	bytndx = bitnum >> 3;
	msk = 1 << (bitnum & 0x7);
	xget(blk)
	IF	( xblk[bytndx] & msk )
	THEN	fprintf(stderr
			,"\7indexfile bitmap says index vbn %ld. is used!\n"
			,vbn);
	FI
END

xuse(vbn)		/* set index file bitmap to say vbn is used */
long	vbn;
BEGIN
int	bytndx;
int	msk;
long	blk;
int	bitnum;
	blk = vbn>>12;
	bitnum = vbn & 0xFFFF;
	bytndx = bitnum >> 3;
	msk = 1 << (bitnum & 0x7);
	xget(blk)
	IF	( ! ( xblk[bytndx] & msk ) )
	THEN	xblk[bytndx] |= msk ;
		xput(blk);
	FI
END

xget(vbn)		/* get vbn'th index bitmap block to xblk[] */
long	vbn;
BEGIN
	IF	(frget(xblk,512,indexf,vbn+homblk.h_iblb))
	THEN	error("\7$$ferr=%oo index bitmap read %loo",$$ferr,vbn);
	FI
END

xput(vbn)		/* put vbn'th index bitmap block from xblk[] */
long	vbn;
BEGIN
return(0);
	IF	(frput(xblk,512,indexf,vbn+homblk.h_iblb))
	THEN	error("\7$$ferr=%oo index bitmap read %loo",$$ferr,vbn);
	FI
END

int	compare(a,b,len)	/* return TRUE if no match */
char	*a;
char	*b;
int	len;
BEGIN

	FOR	(;  len--;  a++,b++)
	DO	IF	(*a!=*b && *a!='%' && *b!='%')
		THEN	return(TRUE);
		FI
	OD
	return(FALSE);
END

constr(dest,stop,pointer)
char *	dest;
char	stop;
char **	pointer;
BEGIN
register	char *	q;
register	char *	p;

	FOR	(q=dest,p=*pointer;	*p && *p!=stop && *q;  p++)
	DO	switch	(*p)
			{
		case '*':	WHILE	(*q)
				DO	*q++ = '%';
				OD
				break;
		default:	*q++ = *p;
				break;
			}
		;
	OD
	/* p points to terminator (usually EOS or stop) */
	*pointer = p;
END

BOOL	isoctal(c)
char	c;
BEGIN
	c &= 0x7F;
	return(c<'8' && c>='0');
END

/* end: find.c */
