diff --git a/.gitignore b/.gitignore index aff4fdb..d685c08 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,34 @@ *~ *.bak *.o +config11/config11 +converters/asc/asc +converters/decsys/decsys +converters/dtos8cvt/dtos8cvt +converters/gt7cvt/gt7cvt +converters/hpconvert/hpconvert +converters/indent/indent +converters/littcvt/littcvt +converters/m8376/m8376 +converters/mt2tpc/mt2tpc +converters/mtcvt23/mtcvtv23 +converters/mtcvtfix/mtcvtfix +converters/mtcvtodd/mtcvtodd +converters/noff/noff +converters/sfmtcvt/sfmtcvt +converters/strrem/strrem +converters/strsub/strsub +converters/tar2mt/tar2mt +converters/tp512cvt/tp512cvt +converters/tpc2mt/tpc2mt +crossassemblers/hpasm/hpasm +crossassemblers/macro1/macro1 +crossassemblers/macro7/macro7 +crossassemblers/macro8x/macro8x +extracters/ckabstape/ckabstape +extracters/mmdir/mmdir +extracters/mtdump/mtdump +extracters/rawcopy/RawCopy +extracters/rstsflx/flx +extracters/sdsdump/sdsdump +extracters/tpdump/tpdump diff --git a/extracters/Makefile b/extracters/Makefile index be52cc8..ec72b86 100644 --- a/extracters/Makefile +++ b/extracters/Makefile @@ -13,6 +13,7 @@ all: cd mmdir && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" cd mtdump && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" cd rawcopy && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" + cd rstsflx && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" cd sdsdump && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" cd tpdump && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" @@ -21,6 +22,7 @@ clean: cd mmdir && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" clean cd mtdump && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" clean cd rawcopy && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" clean + cd rstsflx && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" clean cd sdsdump && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" clean cd tpdump && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" clean @@ -29,6 +31,7 @@ install: cd mmdir && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" install cd mtdump && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" install cd rawcopy && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" install + cd rstsflx && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" install cd sdsdump && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" install cd tpdump && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" install @@ -37,5 +40,6 @@ uninstall: cd mmdir && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" uninstall cd mtdump && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" uninstall cd rawcopy && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" uninstall + cd rstsflx && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" uninstall cd sdsdump && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" uninstall cd tpdump && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" uninstall diff --git a/extracters/rstsflx/BUGS b/extracters/rstsflx/BUGS new file mode 100644 index 0000000..98f905a --- /dev/null +++ b/extracters/rstsflx/BUGS @@ -0,0 +1,7 @@ +open bugs: +- delete does not honor priv (erase on delete) bit +- no readline support in dos +- filename completion does host file system completion, which is usually + the wrong thing +- "put" should pre-extend the output file if in binary copy mode. +- need error checking on I/O diff --git a/extracters/rstsflx/HISTORY b/extracters/rstsflx/HISTORY new file mode 100644 index 0000000..117d273 --- /dev/null +++ b/extracters/rstsflx/HISTORY @@ -0,0 +1,68 @@ +Changes for V2.6: +16.04.27 A couple of bugfixes. Changed license to BSD. + +Changes for V2.5: +00.08.24 Readline support for DOS now appears to be working, + thanks to a newer version of DJGPP. It needs to + be checked out a bit more, though, and there + still seem to be some oddities. + +Changes for V2.4: +00.01.16 Added upper limit check on INIT to hook command so + we don't try to hook an INIT that extends into the + space needed for the bootstrap. This duplicates + a check that exists in hook.sav. +00.01.18 Have "clean" display current dir and filename + even if not -verbose, but all on a single line. +00.01.23 Fix calculation of RE count in fileseek, which was + causing disk block out of range errors sometimes. + +Changes for V2.3: +00.01.02 Fixed eof calculation for RMS fixed files (-rf switch) + Added support for RX50 format 5.25 inch floppy access + in Linux. Added code to get size for raw disks + under Linux, so the -Size switch is no longer needed. + Changed date display format to use 4 digit years, and + fix some Y2K bugs. :-( +00.01.04 Fixed an elusive malloc bug. +00.01.08 Fixed RX50 I/O. + +Changes for V2.2: +99.12.02 Bugfix in RMS mode "get" for 32 bit int targets. + Use fgets instead of gets in scancmd. + +Changes for V2.0: + +- bugfix in protect command: allow file protection code changes even +if P bit is set (as RSTS does) + +- bugfix in rename: disallow rename/replace if new file name == old +name (previous code would delete the file and then crash) + +- bugfix in hook command for environments with 32-bit integers + +- fix platform.h so it may work better in Alphas (not tested for lack +of hardware) + +- change abort handler to use setjmp/longjmp so failure no longer +exits but goes back to command prompt if in prompting mode + +- added -noprotect as synonym for -unprotect + +- bugfix in list -summary: print correct ppns in per-directory summary +line. + +- added clean (rebuild) + +- added -odt and -offset to hook command. + +- bugfix in hook command to set clustersize (for disks whose +clustersize is not always the same) + +- bugfix in quota update if doing multiple directories since start of +program + +- allow [n,*] and [*,*] for gfd and mfd in get and dump commands + +- use GNU readline package, with command line recall including history +file. diff --git a/extracters/rstsflx/LICENSE b/extracters/rstsflx/LICENSE new file mode 100644 index 0000000..a6833ad --- /dev/null +++ b/extracters/rstsflx/LICENSE @@ -0,0 +1,32 @@ +License for RSTSFLX +-------------------- + +Copyright (c) 1994-2016, Paul Koning. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/extracters/rstsflx/Makefile b/extracters/rstsflx/Makefile new file mode 100644 index 0000000..2ea895d --- /dev/null +++ b/extracters/rstsflx/Makefile @@ -0,0 +1,86 @@ +# *** NOTE *** +# This makefile is set up for Linux. It will need some (small) changes to +# build under something else. See notes in comments below, marked with *** + +VERSION = 2.5 + +# objects +OBJS=\ + rstsflx.o \ + fip.o \ + rtime.o \ + filename.o \ + doget.o \ + dolist.o \ + doalloc.o \ + docomp.o \ + dotype.o \ + doput.o \ + dodump.o \ + dodelete.o \ + dorename.o \ + dorts.o \ + doprot.o \ + dodir.o \ + doident.o \ + doinit.o \ + dohook.o \ + scancmd.o \ + doclean.o \ + fileio.o \ + diskio.o \ + absio.o + +# Flags and the like + +# *** change the two lines below as needed for your C compiler. +CC ?= gcc +OPTIMIZE ?= -O2 -g2 +LDFLAGS ?= -g2 + +DEFINES = +CFLAGS = $(OPTIMIZE) $(DEFINES) $(EXTRAFLAGS) + +KITNAME = flx-$(VERSION) +DIR = flx + +# Rules + +S = $(OBJS:.o=.c) +SRCS = $(S:absio.c=unxabsio.c) + +# *** comment out or delete this first rule if not building on DOS +#flx.exe: flx +# strip flx +# coff2exe -s /djgpp/bin/go32.exe flx + +flx: $(OBJS) + $(CC) $(LDFLAGS) -o flx $(OBJS) $(EXTRAOBJS) -lreadline -lncurses $(EXTRAFLAGS) + +# *** the rule below builds absio.o. You need to use as source file +# *** an appropriate file; in Unix that's probably unxabsio.c but check +# *** the source file to be sure. + +absio.o: unxabsio.c + $(CC) -c -o absio.o $(CFLAGS) $< + +# general build rule for all other object files: +.c.o: + $(CC) -c $(CFLAGS) $< + +kit: + rm -f *~ + cd ..; tar cvzf $(KITNAME).tar.gz \ + $(DIR)/README $(DIR)/COPYING $(DIR)/BUGS $(DIR)/HISTORY \ + $(DIR)/Makefile* $(DIR)/*.c $(DIR)/*.h \ + $(DIR)/*.doc $(DIR)/*.pdf $(DIR)/fdprm + +clean: + rm -f *.o flx flx.exe flx.dep + + +flx.dep: + gcc -MM $(SRCS) > flx.dep + +# the one below is created by make depend +include flx.dep diff --git a/extracters/rstsflx/Makefile.dos b/extracters/rstsflx/Makefile.dos new file mode 100644 index 0000000..ecdd2da --- /dev/null +++ b/extracters/rstsflx/Makefile.dos @@ -0,0 +1,133 @@ +# *** NOTE *** +# This makefile is set up for DOS (DJGPP). It will need some (small) +# changes to build under Unix. See notes in comments below, marked with *** + +# sources +# *** note the first one, that's the absolute I/O source module. Change +# *** this to the one appropriate for your OS, for example unxabsio.c +# *** in the case of Unix. + +SRCS=\ + djabsio.c \ + rstsflx.c \ + fip.c \ + rtime.c \ + filename.c \ + doget.c \ + dolist.c \ + doalloc.c \ + docomp.c \ + dotype.c \ + doput.c \ + dodump.c \ + dodelete.c \ + dorename.c \ + dorts.c \ + doprot.c \ + dodir.c \ + doident.c \ + doinit.c \ + dohook.c \ + scancmd.c \ + fileio.c \ + diskio.c + +# prototype header files (none for rstsflx.c and scancmd.c) +PROTOS=\ + rstsflx.h \ + platform.h \ + fip.h \ + rtime.h \ + filename.h \ + doget.h \ + dolist.h \ + doalloc.h \ + docomp.h \ + dotype.h \ + doput.h \ + dodump.h \ + dodelete.h \ + dorename.h \ + dorts.h \ + doprot.h \ + dodir.h \ + doident.h \ + doinit.h \ + doinit.h \ + scancmd.h \ + fileio.h \ + diskio.h + +# objects +OBJS=\ + rstsflx.o \ + fip.o \ + rtime.o \ + filename.o \ + doget.o \ + dolist.o \ + doalloc.o \ + docomp.o \ + dotype.o \ + doput.o \ + dodump.o \ + dodelete.o \ + dorename.o \ + dorts.o \ + doprot.o \ + dodir.o \ + doident.o \ + doinit.o \ + dohook.o \ + scancmd.o \ + doclean.o \ + fileio.o \ + diskio.o \ + absio.o + +# Flags and the like + +# *** change the three lines below as needed for your C compiler. +CC= gcc +CFLAGS= -O3 -Wall +LFLAGS= + +# Rules + +# *** comment out or delete this first rule if not building on DOS +#flx.exe: flx +# strip flx +# coff2exe flx + +flx.exe: $(OBJS) + $(CC) -o flx.exe $(OBJS) -lreadline $(LFLAGS) + +# *** the rule below builds absio.o. You need to use as source file +# *** an appropriate file; in Unix that's probably unxabsio.c but check +# *** the source file to be sure. + +absio.o: djabsio.c + $(CC) -c -o absio.o $(CFLAGS) $< + +# general build rule for all other object files: +.c.o: + $(CC) -c $(CFLAGS) $< + +kit: + tar cvzf ../flx.tar.gz flx.exe \ + Makefile* *.c *.h *.doc *.ps *.txt *.html \ + README COPYING BUGS HISTORY + zip ../flx.zip flx.exe \ + Makefile* *.c *.h *.doc *.ps *.txt *.html \ + README COPYING BUGS HISTORY + +clean: + del *.o + del flx + del flx.exe + +depend: + gcc -MM *.c > flx.dep + +# the one below is created by make depend +include flx.dep diff --git a/extracters/rstsflx/README b/extracters/rstsflx/README new file mode 100644 index 0000000..72008a3 --- /dev/null +++ b/extracters/rstsflx/README @@ -0,0 +1,25 @@ +README file for FLX 1/11/2000 + +What you have here is the set of sources needed to build FLX, a +Makefile to do it, and documentation (in PostScript and the source in +MS Word format). + +Note on the Makefile: it has been used both with Mips Ultrix "cc" and +with gcc (with DOS and with Linux), but "make proto" only works with +cc since gcc doesn't support the -protoi switch. Don't worry about +that unless you change the sources in a way that affects the procedure +prototype declarations. (If you do, edit the .h file of the same name +as the .c file to reflect the changed prototypes.) + +As far as I know, everything that's described in flx.ps should work. +Let me know if you find problems. (I'll admit that I haven't tested +all the cases. For example, RDS0.0 support has had limited testing. +And I don't have a "large" disk to test large DCS support!) + +I've had very little feedback on this program. If you use it, even +if you have no comments on it, I'd appreciate a short note. And of +course if you do have comments, bug reports, or suggestions, then +definitely let me know! + + paul koning + ni1d@arrl.net diff --git a/extracters/rstsflx/absio.h b/extracters/rstsflx/absio.h new file mode 100644 index 0000000..de5f9ca --- /dev/null +++ b/extracters/rstsflx/absio.h @@ -0,0 +1,6 @@ +extern void absname (const char *rname); +extern int absopen (const char *rname, const char *mode); +extern void absseek (long block); +extern long absread (long sec, long count, void *buffer); +extern long abswrite (long sec, long count, void *buffer); +extern void absclose (void); diff --git a/extracters/rstsflx/borabsio.c b/extracters/rstsflx/borabsio.c new file mode 100644 index 0000000..73050db --- /dev/null +++ b/extracters/rstsflx/borabsio.c @@ -0,0 +1,42 @@ +/* absread and abswrite services for use with Borland C implementation + * + * Paul Koning 95.01.17 Dummy module (no absio in TC++ for Windows) + */ + +#include +#include + +#include "flx.h" +#include "absio.h" + +/* this routine is called to scan a supplied container file/device + * name. If the name refers to a real disk, then absflag is set + * and rsize is set to the device size. Otherwise, no action is taken. + */ + +void absname (const char *rname) +{ + if (rname[strlen(rname) - 1] == ':') { /* device name alone */ + printf ("Absolute I/O not supported\n"); + } +} + +int absopen (const char *rname, const char *mode) +{ + return (1); /* should never get here... */ +} + +void absseek (long block) { } /* nothing to do */ + +void absclose () { } /* nothing to do */ + +long absread (long sec, long count, void *buffer) +{ + return (0); /* should never get here... */ +} + +long abswrite (long sec, long count, void *buffer) +{ + return (0); /* should never get here... */ +} + diff --git a/extracters/rstsflx/diskio.c b/extracters/rstsflx/diskio.c new file mode 100644 index 0000000..fb6b4c4 --- /dev/null +++ b/extracters/rstsflx/diskio.c @@ -0,0 +1,262 @@ +/* subroutines to do rsts disk (logical block) I/O */ + +#include +#include +#include +#include +#include +#include + +#include "flx.h" +#include "diskio.h" +#include "absio.h" + +#define DEFDEVICE "rsts.dsk" + +#define NOLAST 0 +#define LASTREAD 1 +#define LASTWRITE 2 + +#ifndef S_ISCHR +#define S_ISCHR(x) (((x) & S_IFMT) == S_IFCHR) +#endif + +typedef struct { + const char *name; /* Name of the disk */ + long tsize; /* Total container size */ + long rsize; /* Size RSTS uses */ + int dec166; /* TRUE if disk has factor bad block table */ +} diskent; + +int dcs; /* device clustersize */ +long diskblocks; /* device block count */ +const char *rname; /* file name of disk/container */ +const char *rssize; /* and associated size */ +long rsize; /* explicitly supplied size (for real disks) */ +int absflag; /* doing absolute I/O to real disk if non-zero */ +FILE *rstsfile; /* rsts disk or container file */ + +int lastio; /* what type of I/O, if any, was last done */ +long nextblk; /* next block after end of last I/O */ + +const diskent sizetbl[] = { + { "rx50", 800, 800, FALSE }, + { "rf11", 1024, 1024, FALSE }, + { "rs03", 1024, 1024, FALSE }, + { "rs04", 2048, 2048, FALSE }, + { "rk05", 4800, 4800, FALSE }, + { "rl01", 10240, 10220, TRUE }, + { "rl02", 20480, 20460, TRUE }, + { "rk06", 27126, 27104, TRUE }, + { "rk07", 53790, 53768, TRUE }, + { "rp04", 171798, 171796, FALSE }, + { "rp05", 171798, 171796, FALSE }, + { "rp06", 340670, 340664, FALSE }, + { "rp07", 1008000, 1007950, TRUE }, + { "rm02", 131680, 131648, TRUE }, + { "rm03", 131680, 131648, TRUE }, + { "rm05", 500384, 500352, TRUE }, + { "rm80", 251328, 242575, TRUE }, + { NULL, 0, 0, 0 }}; + +/* getsize takes as input a container file size specifier, which is either + * a decimal string or a disk type name, and returns the corresponding + * size. In the case of disk names, it returns both the size as RSTS + * knows it, and the full hardware-defined size. In addition, it returns + * a flag indicating whether that type has a bad block table. + * In the case of a numeric size, it looks for a match in the table + * (against either RSTS size or "full" size) and returns what the + * table entry specifies. If no match is found, it returns the + * specified value for both and the dec166 flag is false. + * If the size specifier is invalid, the RSTS size is returned as zero + * and the other two return values are undefined. + */ + +void getsize (const char *name, long *tsize, long *rsize, int *dec166) +{ + const diskent *d; + char *n, *n2, *pp; + + if (isdigit (*name)) /* numeric size given */ + { + *rsize = strtoul (name, &pp, 10); /* scan size */ + if (*pp != '\0') *rsize = 0; + *tsize = *rsize; + *dec166 = FALSE; + for (d = sizetbl; d->name != NULL; d++) + if (d->rsize == *rsize || d->tsize == *rsize) + { + *tsize = d->tsize; + *rsize = d->rsize; + *dec166 = d->dec166; + break; + } + } + else + { + if ((n = (char *) malloc (strlen (name) + 1)) == NULL) rabort(NOMEM); + strcpy (n, name); + for (n2 = n; *n2; n2++) *n2 = tolower (*n2); + for (d = sizetbl; d->name != NULL; d++) + if (strcmp (d->name, n) == 0) break; + free (n); + *tsize = d->tsize; + *rsize = d->rsize; + *dec166 = d->dec166; + } +} + +/* adjsize takes as input a container file size. it returns the + * corresponding RSTS size, based on a match against a table of + * known disk sizes. if it finds a match, it returns the RSTS + * size given in the table; otherwise it returns the value that + * was passed. + */ + +long adjsize (long tsize) +{ + const diskent *d; + + for (d = sizetbl; d->name != NULL; d++) + if (d->tsize == tsize) + return d->rsize; + return tsize; +} + +void setrname () +{ + long t1; + int t2; + + if ((rname = sw.rstsdevice) == NULL) + if ((rname = defdevice) == NULL) + if ((rname = getenv ("RSTSDISK")) == NULL) + rname = DEFDEVICE; + if ((rssize = sw.disksize) == NULL) + if ((rssize = defsize) == NULL) + if ((rssize = getenv ("RSTSDISKSIZE")) == NULL) + rssize = NULL; + rsize = 0; + absflag = FALSE; + if (rssize != NULL) { + getsize (rssize, &t1, &rsize, &t2); /* scan size */ + if (rsize == 0) { + printf ("Invalid device size %s\n", rssize); + return; /* and quit */ + } + } + absname (rname); /* see if name is special */ + if (absflag && rsize == 0) { + printf ("Disk size must be specified explicitly for disk %s\n", + rname); + return; + } +} + +void ropen (const char *mode) +{ + long d; + struct stat sbuf; + + fiblk = -1; /* indicate no valid FIBUF */ + lastio = NOLAST; /* and no previous I/O */ + womsat = FALSE; /* SATT is clean */ + setrname (); + if (absflag) { /* open real disk */ + if (absopen (rname, mode)) { + printf ("Error opening RSTS device %s\n", rname); + perror (progname); /* report any details */ + rabort (NOMSG); + } + diskblocks = rsize; /* set block count */ + } else { /* not absolute disk */ + if ((rstsfile = fopen (rname, mode)) == NULL) { + printf ("Error opening RSTS device %s\n", rname); + perror (progname); /* report any details */ + rabort (NOMSG); + } + if (fstat (fileno(rstsfile), &sbuf)) { /* get info about disk/file */ + printf ("Can't stat RSTS device %s", rname); + perror (progname); + fclose (rstsfile); /* close it */ + rabort (NOMSG); + } + diskblocks = UP(sbuf.st_size,BLKSIZE) / BLKSIZE; + if (diskblocks == 0) { + if (!S_ISCHR(sbuf.st_mode) && + !S_ISBLK(sbuf.st_mode)) + { + printf ("Null RSTS container file %s\n", rname); + fclose (rstsfile); + rabort (NOMSG); + } + if (rsize == 0) { + printf ("Size not specified for RSTS disk %s\n", rname); + fclose (rstsfile); + rabort (NOMSG); + } + diskblocks = rsize; + } + } + diskblocks = adjsize (diskblocks); /* adjust for bad block tbl */ + d = (diskblocks - 1) >> 16; /* high order bits of last LBN */ + dcs = 1; /* compute DCS */ + while (d) { + d >>= 1; + dcs <<= 1; + } + if (dcs > 64) rabort(BADDCS); /* Sorry, disk too big! */ +} + +void rseek (long block) +{ + if (block >= diskblocks) rabort(BADBLK); + if (absflag) absseek (block); + else fseek (rstsfile, block * BLKSIZE, SEEK_SET); + if (sw.debug != NULL) + printf ("seek to: %ld\n", block); +} + +void rread (long block, long size, void *buffer) +{ + long iosize; + + if (lastio != LASTREAD || nextblk != block) { + rseek (block); + lastio = LASTREAD; + } + if (absflag) { + if (absread (block, size, buffer)) + iosize = 0; + else iosize = size; + } + else iosize = fread (buffer, 1, size, rstsfile); + if (sw.debug != NULL) + printf ("size requested: %ld, read: %ld\n", size, iosize); + if (iosize != size) rabort(DISKIO); + nextblk = block + size / BLKSIZE; +} + +void rwrite (long block, long size, void *buffer) +{ + long iosize; + + if (lastio != LASTWRITE || nextblk != block) { + rseek (block); + lastio = LASTWRITE; + } + if (absflag) { + if (abswrite (block, size, buffer)) + iosize = 0; + else iosize = size; + } + else iosize = fwrite (buffer, 1, size, rstsfile); + if (iosize != size) rabort(DISKIO); + nextblk = block + size / BLKSIZE; +} + +void rclose () +{ + if (absflag) absclose (); + else fclose (rstsfile); +} diff --git a/extracters/rstsflx/diskio.h b/extracters/rstsflx/diskio.h new file mode 100644 index 0000000..1e0d424 --- /dev/null +++ b/extracters/rstsflx/diskio.h @@ -0,0 +1,8 @@ +extern void getsize (const char *name, long *tsize, long *rsize, int *dec166); +extern long adjsize (long size); +extern void setrname(void); +extern void ropen(const char * mode); +extern void rseek(long block); +extern void rread(long block , long size , void * buffer); +extern void rwrite(long block , long size , void * buffer); +extern void rclose(void); diff --git a/extracters/rstsflx/djabsio.c b/extracters/rstsflx/djabsio.c new file mode 100644 index 0000000..18dc96b --- /dev/null +++ b/extracters/rstsflx/djabsio.c @@ -0,0 +1,304 @@ +/* absread and abswrite services for use with DJGPP GNU C implementation + * + * Paul Koning 94.10.16 + * 94.11.18 added bios i/o + * 94.11.21 dos i/o for hard disk, bios i/o for floppy + * 94.12.19 add retry for bios I/O + * 95.01.05 update for generalized abs i/o in flx + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "flx.h" +#include "absio.h" + +#define tb _go32_info_block.linear_address_of_transfer_buffer + +#define BIOSBUF (_go32_info_block.size_of_transfer_buffer) + /* size of djgpp bios disk I/O buffer */ +#define BIOSMAX (18 * BLKSIZE) /* max size in biosdisk() call */ +#define BIOSRESET 0 /* error reset */ +#define BIOSREAD 2 /* bios disk read function code */ +#define BIOSWRITE 3 /* bios disk write function code */ +#define BIOSTRIES 4 /* retry count */ +#define ABSREAD 0x25 /* abs read int code */ +#define ABSWRITE 0x26 /* abs write int code */ +#define BIOS_DATA_SEG 0x0040 /* BIOS data segment number */ +#define BIOS_DSK_STATE 0x0090 /* offset to drive 0 media state */ +#define DISK_STATE(d) ((BIOS_DATA_SEG << 4) + BIOS_DSK_STATE + ((d) - 1)) + +#define BIOS_DSK_360K 0x74 /* 360kb media established */ +#define BIOS_DSK_RX50 0x54 /* RX50 media established in drive */ + /* (same as 360kb except single steps */ + /* for 96 tpi media) */ + +static int secsize = 0; +static int param_segment = 0; +static unsigned short int dosparam[5]; +static int rxflag = 0; /* set if accessing 5.25 inch floppy */ +static int gdrive = -1; /* drive to which geometry data applies */ +static int drive; /* disk unit number currently open */ +static int sectors, heads, cylinders, drives; +static _go32_dpmi_seginfo param_info; + +/* The param_buffer is used to hold the dos abs disk I/O parameter block + */ + +static void free_param_buffer() +{ + _go32_dpmi_free_dos_memory(¶m_info); + param_segment = 0; +} + +static void alloc_param_buffer() +{ + if (param_segment) return; + param_info.size = UP(sizeof(param_info),16) / 16; + if (_go32_dpmi_allocate_dos_memory(¶m_info)) { + param_segment = 0; + return; + } + param_segment = param_info.rm_segment; + atexit(free_param_buffer); +} + +/* convert dos style drive number to bios style number */ + +static int biosdrive (int drive) +{ + if (drive < 3) return (drive - 1); + else return ((drive - 3) + 0x80); /* need to do partitions */ +} + +/* do bios I/O with retries */ + +static int biosdiskr (int func, int drive, int track, int cyl, + int sec, int count, void *buffer, int dparam) +{ + int tries, status; + + for (tries = 0; tries < BIOSTRIES; tries++) { + if (dparam) dosmemput (&dparam, 1, DISK_STATE(drive)); + status = biosdisk (func, biosdrive (drive), track, cyl, + sec, count, buffer); + if (status == 0) break; + + /* strictly speaking one should do error classification + * at this point... + */ + biosdisk (BIOSRESET, biosdrive (drive), 0, 0, 0, 0, NULL); + } + return (status); +} + +static void getgeom (int drive) +{ + _go32_dpmi_registers r; + + gdrive = drive; + memset(&r, 0, sizeof(r)); + r.h.ah = 8; + r.h.dl = biosdrive (drive); + _go32_dpmi_simulate_int(0x13, &r); + heads = r.h.dh + 1; + drives = r.h.dl; + cylinders = r.h.ch + ((r.h.cl >> 6) << 8) + 1; + sectors = r.h.cl & 0x3f; + if (drive < 3 && (r.h.bl & 0x0f) == 2) /* floppy && drive = 1.2MB */ + rxflag = 1; + else rxflag = 0; +} + +/* Convert block number to cylinder, head, sector for RT11-RX50. + * This is different for RT11 than for Rainbow DOS: + * For DOS, for cylinders 2 through 79, the sectors are interleaved 2:1. + * (DOS capability is not supported in this RT11 version). + * For RT11, all sectors are interleaved 2:1, and each subsequent + * track has the first logical block offset by 2 more sectors. + */ + +static void makechs_rx50 (int block, int *trk, int *sec) +{ + int t, s; + + t = block / 10; + s = block % 10 + 1; + if (s < 6) s = (s - 1) * 2 + 1; + else s = (s - 5) * 2; + s += t * 2; + while (s > 10) s -= 10; + t++; + if (t == 80) t = 0; /* wrap around last 10 blocks */ + *trk = t; + *sec = s; +} + +/* do single block disk I/O to DEC RX50 floppy */ +static int rx50io (int func, int drive, int dsksec, void *buffer) +{ + byte oldstate; + int cyl, sec; + int status; + + alloc_param_buffer(); + + /* save old state and set up for RX50 I/O */ + dosmemget (DISK_STATE(drive), 1, &oldstate); + makechs_rx50 (dsksec, &cyl, &sec); + status = biosdiskr (func, drive, 0, cyl, sec, 1, buffer, BIOS_DSK_RX50); + + /* restore BIOS state as it was on entry */ + dosmemput (&oldstate, 1, DISK_STATE(drive)); + return (status); +} + +/* do bios disk I/O call + * if this is a 5.25" floppy, we do the required magic to read it as + * a DEC RX50 format floppy. + */ + +static long biosio (int func, int drive, long dsksec, long count, void *buffer) +{ + long track, sec, cyl; + long tcount, status; + + if (drive != gdrive) getgeom (drive); + while (count) { + if (rxflag) { + tcount = BLKSIZE; + status = rx50io (func, drive, dsksec, buffer); + } else { + tcount = count; + if (tcount > BIOSMAX) tcount = BIOSMAX; + sec = dsksec % sectors; + if ((sectors - sec) * BLKSIZE < tcount) + tcount = (sectors - sec) * BLKSIZE; + sec++; /* weird 1-based numbering */ + track = (dsksec / sectors) % heads; + cyl = dsksec / (sectors * heads); + status = biosdiskr (func, drive, track, cyl, + sec, tcount / BLKSIZE, buffer, 0); + } + if (status) return (status); + count -= tcount; + buffer += tcount; + dsksec += (tcount / BLKSIZE); + } + return (0); +} + +/* do absolute dos disk read/write + * arguments: + * function code (0x25 = read, 0x26 = write) + * drive number (1 = a:, etc) + * starting sector number + * byte count (must be multiple of sector size) + * buffer pointer + */ + +static long dosio (int func, int drive, int sec, long count, void *buffer) +{ + long tcount; + _go32_dpmi_registers r; + + while (count) { + tcount = count; + if (tcount > BIOSBUF) tcount = BIOSBUF; + alloc_param_buffer(); + dosparam[0] = sec & 0xffff; + dosparam[1] = sec >> 16; + dosparam[2] = (tcount / secsize) & 0xffff; + dosparam[3] = (unsigned int) tb & 15; + dosparam[4] = (unsigned int) tb >> 4; + dosmemput(dosparam, sizeof(dosparam), param_segment << 4); + if (func == ABSWRITE) + dosmemput(buffer, tcount, tb); + memset(&r, 0, sizeof(r)); + r.h.al = drive - 1; /* 0-based numbering here */ + r.x.ds = param_segment; + r.x.bx = 0; + r.x.cx = -1; + _go32_dpmi_simulate_int(func, &r); + if (func == ABSREAD) + dosmemget(tb, tcount, buffer); + if (r.x.flags & 1) + return (r.h.al); + count -= tcount; + buffer += tcount; + sec += (tcount / secsize); + } + return (0); +} + +/* return size of specified disk, in blocks. Saves sector size in a local + * static variable as a side effect. A flag is set if the disk is a + * 5.25 inch floppy. + * Note: this must be called before any abs I/O is done. + */ + +static int disksize (int drive) +{ + _go32_dpmi_registers r; + + if (drive >= 3) { /* hard disk */ + memset(&r, 0, sizeof(r)); + r.h.ah = 0x1c; + r.h.dl = drive; + _go32_dpmi_simulate_int(0x21, &r); + secsize = r.x.cx; + return (r.h.al * r.x.dx * secsize / BLKSIZE); + } else { + getgeom (drive); + secsize = 512; + return (cylinders * heads * sectors); + } +} + +/* this routine is called to scan a supplied container file/device + * name. If the name refers to a real disk, then absflag is set + * and rsize is set to the device size. Otherwise, no action is taken. + */ + +void absname (const char *rname) +{ + if (rname[strlen(rname) - 1] == ':') { /* device name alone */ + absflag = TRUE; + drive = tolower (rname[0]) - 'a' + 1; /* set drive number */ + rsize = disksize (drive); + if (sw.debug != NULL) + printf ("disk size for drive %d is %ld\n", drive, rsize); + } +} + +int absopen (const char *rname, const char *mode) +{ + return (0); /* always ok, nothing to do */ +} + +void absseek (long block) { } /* nothing to do */ + +void absclose () { } /* nothing to do */ + +long absread (long sec, long count, void *buffer) +{ + if (drive >= 3) /* hard disk */ + return (dosio (ABSREAD, drive, sec, count, buffer)); + else + return (biosio (BIOSREAD, drive, sec, count, buffer)); +} + +long abswrite (long sec, long count, void *buffer) +{ + if (drive >= 3) /* hard disk */ + return (dosio (ABSWRITE, drive, sec, count, buffer)); + else + return (biosio (BIOSWRITE, drive, sec, count, buffer)); +} + diff --git a/extracters/rstsflx/doalloc.c b/extracters/rstsflx/doalloc.c new file mode 100644 index 0000000..eabbe78 --- /dev/null +++ b/extracters/rstsflx/doalloc.c @@ -0,0 +1,58 @@ +/* handler for the "allocation" command */ + +#include +#include + +#include "flx.h" +#include "fldef.h" +#include "doalloc.h" +#include "fip.h" + +void doalloc (int argc, char **argv) /* show allocated clusters */ +{ + byte *s; + int bit, szb; + long first, used, unused, biggest, size; + long n; + + rmount (); /* mount the disk R/O */ + findsat (); /* look up satt.sys */ + s = sattbufp; + szb = (diskblocks - dcs) / pcs; /* satt bits actually used */ + bit = 1; + n = 0; /* start looking at PCN = 0 */ + used = unused = biggest = 0; /* nothing used, nor unused */ + if (sw.bswitch == NULL) printf ("\nFree pack cluster number ranges:\n"); + for (;;) { + for ( ; n < szb; n++) { + if (bit > 0x80) { + bit = 1; + s++; + } + if ((*s & bit) == 0) break; + used++; /* count allocated clusters */ + bit <<= 1; + } + if (n == szb) break; + first = n; + for ( ; n < szb; n++) { + if (bit > 0x80) { + bit = 1; + s++; + } + if (*s & bit) break; + unused++; /* count free clusters */ + bit <<= 1; + } + size = (n - first) * pcs; + if (size > biggest) biggest = size; + if (sw.bswitch == NULL) { + printf ("%6ld - %-6ld (%ld blocks)\n", first, n - 1, size); + } + } + printf ("Blocks used: %ld, free: %ld, max contiguous free: %ld\n", + used * pcs, unused * pcs, biggest); + free (sattbufp); /* release the satt memory copy */ + rumount (); /* done with the disk */ +} + diff --git a/extracters/rstsflx/doalloc.h b/extracters/rstsflx/doalloc.h new file mode 100644 index 0000000..de3eb64 --- /dev/null +++ b/extracters/rstsflx/doalloc.h @@ -0,0 +1 @@ +extern void doalloc(int argc , char ** argv); diff --git a/extracters/rstsflx/doclean.c b/extracters/rstsflx/doclean.c new file mode 100644 index 0000000..8f57916 --- /dev/null +++ b/extracters/rstsflx/doclean.c @@ -0,0 +1,1794 @@ +/* handler for the "clean" (or "rebuild") command */ + +/* this code is inspired by the INICLN module of RSTS INIT, with some + * significant changes: + * 1. support for "read-only" clean, i.e., look, do not touch. + * 2. directories are read in entirely and manipulated in memory. + * this speeds things up a lot and eliminates the need for the + * disk cache that ONLCLN maintains. + * 3. blockette use status is kept in a separate bitmap rather than + * in the link words on disk. this avoids two write passes and + * allows a totally read-only clean to be done. + * 4. if a double allocation is found, the offending file is truncated + * (if it's a directory, it is zeroed). you don't get the option + * to delete the file it conflicts with. that saves a *lot* of code. + */ +#include +#include +#include +#include + +#include "flx.h" +#include "fldef.h" +#include "diskio.h" +#include "filename.h" +#include "doclean.h" +#include "fip.h" +#include "rtime.h" + +#define dirbufsize (7 * 16 * BLKSIZE) +#define dirmapsize (7 * 16 * BLKSIZE / sizeof (gfdne) / 8) +#define PPN11 0401 + +/* pointers to buffers used by clean. to speed things up, we use + * lots of memory and read whole file system structures into memory. + * specifically we use: + * sattbf2 - storage allocation table (same form as sattbuf) + * badbmap - map of bad blocks (same form as sattbuf) + * mfdbuf - the entire MFD + * mfdmap - bitmap of allocated MFD blockettes + * gfdbuf - the entire current GFD + * gfdmap - bitmap of allocated GFD blockettes + * ufdbuf - the entire current UFD + * ufdmap - bitmap of allocated UFD blockettes + * + * note: the blockette maps don't explicitly represent the label or + * fdcm spots, since those are in use by definition. however, the + * label position (LSB of first byte) is used as a "dirty buffer" + * marker for the corresponding directory buffer. + */ + +#define MARK(map) *(map) |= 1 + +typedef enum +{ + ok, badblock, dup, badlink, nullink, other, + range, align, delete +} retcode; + +byte *sattbf2 = NULL; +byte *badbmap = NULL; +byte *mfdbuf = NULL; +byte *mfdmap = NULL; +byte *gfdbuf = NULL; +byte *gfdmap = NULL; +byte *ufdbuf = NULL; +byte *ufdmap = NULL; + +byte curproj, curprog; +char curdir[10]; +char curfile[22]; +long filesize; +long e; +long gfds, ufds, files, clusters; +long dirfiles, dirtsize; +int badb, satt, init; /* flags for special files */ + +/* get a yes or no answer; return true if yes, false if no. + * loop until a valid answer is received. the default is "no". + * if -protect switch (read-only clean) was present, supply + * a "yes" answer automatically (note that this won't actually + * cause any changes, but it will allow the process to continue). + */ +static retcode yesno (void) +{ + char c; + char answer[LSIZE]; + int cmdlen; + + if (sw.prot != NULL) + { + printf ("Yes (read-only)\n"); + return other; + } + for (;;) + { + if (fgets (answer, LSIZE, stdin) == NULL) return FALSE; + cmdlen = strlen (answer); + if (answer[cmdlen - 1] == '\n') + answer[--cmdlen] = '\0'; + else + { + printf ("Reply too long\nYes or No? "); + continue; + } + c = toupper (answer[0]); + if (c == 'Y') return ok; + else if (c == 'N' || c == '\0') return other; + printf ("Invalid answer\nYes or No? "); + } +} + +/* similarly but a "no" answer aborts the clean */ +static void yes (void) +{ + printf ("\nProceed (Yes or No)? "); + if (yesno () == ok) return; + printf ("Clean aborted\n"); + rabort (NOMSG); +} + +/* this function reads an entire directory into the designated buffer. + * it assumes the supplied dcn is valid. it uses the first fdcm to + * find all the other clusters, but does not do full validation on + * the fdcm -- only enough to avoid making a mess of the reads. + * it's the caller's job to do more detailed checks. + * + * on the assumption that a directory often has a clustersize of 16, + * and in any case may be more or less contiguous, we start with a + * read of 16 blocks. + */ +static void readdir (word dcn, byte *buf) +{ + int i, clu; + long j, start, blks; + fdcm *m; + byte *p; + + if (sw.debug != NULL) + printf ("\nreaddir(%d,%p)", dcn, buf); + start = dcntolbn (dcn); + if ((diskblocks - start) < 16) + blks = diskblocks - start; + else blks = 16; + if (blks < 1) rabort (INTERNAL); + rread (start, BLKSIZE * blks, buf); + m = (fdcm *) (buf + 0760); + clu = m->uclus; + if (dcn != m->uent[0] || /* some simple sanity checks... */ + clu > blks || + (pcs <= 16 && clu < pcs) || + (clu & (-clu)) != clu) + return; + p = buf + (BLKSIZE * clu); /* point to second cluster's data */ + i = 1; /* and next r.e. index to use */ + if (clu != blks) /* read more than a cluster? */ + { + j = clu / dcs; /* dcn increment if contiguous */ + for (;;) + { + if (i == 7 || i * clu >= blks) return; + if (m->uent[i] == 0) return; + if (m->uent[i] != m->uent[i - 1] + j) break; + if (sw.debug != NULL) + printf (" entry %d, dcn %d is contiguous", + i, m->uent[i]); + i++; + p += BLKSIZE * clu; + } + } + for ( ; i < 7; i++) + { + if (m->uent[i] == 0) return; /* done */ + j = dcntolbn (m->uent[i]); + if (sw.debug != NULL) + printf (" read entry %d, dcn %ld, %d blocks", + i, j, clu); + if (j >= diskblocks) return; /* out of range, quit */ + rread (j, BLKSIZE * clu, p); + p += BLKSIZE * clu; + } +} + +/* this function writes back a directory. no validation is done, since + * that was all done before. + */ +static void writedir (byte *buf) +{ + int i, clu; + long j; + fdcm *m; + byte *p; + + if (sw.prot != NULL) return; /* read-only, don't write */ + m = (fdcm *) (buf + 0760); + clu = m->uclus; + for (i = 0 ; i < 7; i++) + { + if (m->uent[i] == 0) return; /* done */ + j = dcntolbn (m->uent[i]); + rwrite (j, BLKSIZE * clu, buf); + buf += BLKSIZE * clu; + } +} + +/* this function is like the standard function ulk (in fip.c) except + * that it operates on a previously read directory in its buffer. + * i and k are set as usual; in addition, e (for "entry") is set to + * be a byte offset to the entry. + */ + +retcode ulk2 (word link, byte *buf) +{ + int clu, blk; + fdcm *m; + + if (NULLINK (link)) return nullink; + m = (fdcm *) (buf + 0760); + k = (link & ul_eno); /* k = byte offset to entry */ + clu = (link & ul_clo) >> sl_clo; /* cluster number */ + blk = (link & ul_blo) >> sl_blo; /* block in cluster */ + if (sw.debug != NULL) + printf ("\nulk2(%o), k=%lo, clu=%d, blk=%d, clumap=%d", + link, k, clu, blk, m->uent[clu]); + if (blk >= m->uclus || + clu > 6 || + k == 0760 || + m->uent[clu] == 0) + return badlink; + i = blk + dcntolbn(m->uent[clu]); /* LBN of entry */ + e = k + (clu * m->uclus + blk) * BLKSIZE; + return ok; /* ok */ +} + +/* function to read an entry into fibuf given a link, with validity + * checking but no abort for bad links. + */ +retcode readlkchk (word link) +{ + if (NULLINK(link)) return nullink; /* indicate null link */ + if (ulk (link)) return badlink; /* unpack and check link */ + fbread (i); /* read the directory block */ + return ok; +} + +/* function to mark a directory entry as allocated. it takes a pointer + * to the entry map to update. the entry marked is the one most recently + * referenced in a call to ulk2. + */ +static retcode allocent (byte *map) +{ + int ent, bpos, m; + + if (e == 0 || k == 0760) rabort (INTERNAL); + ent = e / sizeof (gfdne); /* entry number */ + bpos = ent / 8; /* byte offset */ + m = 1 << (ent % 8); /* mask to touch */ + if (map[bpos] & m) return dup; /* error if already marked */ + map[bpos] |= m; + return ok; +} + +/* similarly, mark entry as deallocated */ +static void deallocent (byte *map) +{ + int ent, bpos, m; + + if (e == 0 || k == 0760) rabort (INTERNAL); + ent = e / sizeof (gfdne); /* entry number */ + bpos = ent / 8; /* byte offset */ + m = 1 << (ent % 8); /* mask to touch */ + if (((map[bpos] & m) == 0)) + rabort (INTERNAL); /* error if not marked */ + map[bpos] &= ~m; +} + +/* mark a chain of directory blockettes as allocated (but do no + * other processing on them). this is used for attribute chains + * and the like. the "use" argument is non-zero to force the link + * word of each entry to have the ul_use bit set. + * it returns 0 if all is ok, or the last good link (i.e., the link for + * the entry that contains the problem link) if there is a problem. + * a suitable message is printed to indicate the problem. if the + * first link is bad, the return value is 1. this allows the caller + * to truncate the chain. entries up to the problem spot are still + * marked as allocated. + */ +static word allocchain (word link, byte *buf, byte * map, int use) +{ + word prev = 1; + retcode st; + + for (;;) + { + st = ulk2 (link, buf); + if (st == nullink) return 0; /* end of chain, success */ + if (st == badlink) + { + printf ("invalid link "); + break; + } + /* ok, so the link is good. does it point to a real entry? */ + if (*(lword32 *) (buf + e) == 0) + { + printf ("entry is a hole "); + break; + } + st = allocent (map); + if (st != ok) + { + printf ("doubly allocated entry "); + break; + } + prev = link; + link = *(word16 *) (buf + e); /* follow link to next */ + if (use && (link & ul_use) == 0) + { + if (sw.debug != NULL) + printf ("\nfixed link word for entry at offset %06lo\n", + e); + *(word16 *) (buf + e) |= ul_use; + MARK (map); + } + } + return prev; /* we had a problem */ +} + +/* similarly, mark a chain as free. */ +static void deallocchain (word link, byte *buf, byte * map) +{ + retcode st; + + for (;;) + { + st = ulk2 (link, buf); + if (st == nullink) return; /* end of chain, done */ + if (st == badlink) rabort (INTERNAL); + deallocent (map); + link = *(word16 *) (buf + e); /* follow link to next */ + } +} + +/* function to mark a cluster as allocated. this operates on sattbf2 + * (not sattbuf) -- it looks a lot like retclu except for the sense of + * the change... + */ + +static retcode alloc (word pos, int clusiz) +{ + long m, n; + byte *s; + int bpos; + retcode ret = ok; + + if (sw.debug != NULL) + printf ("\nalloc(%d,%d)", pos, clusiz); + if (clusiz < dcs && dcs > 16) + clusiz = dcs; /* deal with directories on large disks */ + if ((pos - 1) % (clusiz / dcs)) + return align; + pos = dcntopcn(pos); /* convert to pcn */ + if (pos >= pcns) + return range; + clusiz /= pcs; /* fcs as count of clusters */ + if (clusiz <= 0) + rabort (INTERNAL); + bpos = pos / 8; /* byte offset to start of cluster */ + if (clusiz < 8) /* scanning bitwise */ + { + m = (1 << clusiz) - 1; /* mask to match on */ + m <<= (pos % 8); /* form starting bit field */ + if (badbmap[bpos] & m) + ret = badblock; /* bad block, remember it */ + if (sattbf2[bpos] & m) + return dup; /* double allocation */ + sattbf2[bpos] |= m; /* ok, allocate it */ + clusters += clusiz; /* update stats */ + } + else /* scanning whole bytes */ + { + clusiz /= 8; /* change to count of bytes to alloc */ + for (n = 0; n < clusiz; n++) + if (badbmap[bpos + n]) + ret = badblock; /* bad block, remember it */ + for (n = 0; n < clusiz; n++) + if (sattbf2[bpos + n]) + return dup; /* double allocation */ + for (n = 0; n < clusiz; n++) + sattbf2[bpos + n] = 0xff; /* ok, allocate it */ + clusters += clusiz * 8; /* update stats */ + } + + return ret; +} + +/* sometimes we have to deallocate something -- to clean up from + * allocating something that then messes up halfway. + * this code is straight from fip.c retclu except for the use of + * a different buffer. + */ +static void dealloc (word pos, int clusiz) +{ + long m, n; + byte *s; + + if (sw.debug != NULL) + printf ("\ndealloc(%o,%d)", pos, clusiz); + if (sattsize == 0) + rabort (INTERNAL); + pos = dcntopcn(pos); /* convert to pcn */ + clusiz /= pcs; /* fcs as count of clusters */ + if (clusiz == 0 && pcs > 16) + clusiz = 1; /* handle directories on large disks */ + if (clusiz <= 0) + rabort (INTERNAL); + s = sattbf2 + pos / 8; /* byte pointer to start of cluster */ + if (clusiz < 8) /* scanning bitwise */ + { + m = (1 << clusiz) - 1; /* mask to match on */ + m <<= (pos % 8); /* form starting bit field */ + *s &= ~m; /* free this cluster */ + } + else /* scanning whole bytes */ + { + clusiz /= 8; /* change to count of bytes to free */ + for (n = 0; n < clusiz; n++) + *s++ = 0; + } +} + +/* common directory cleanup + * this function reads a directory into the indicated buffer, clears + * out the blockette map, and validates all the fdcm's. if it's happy, + * it returns ok or badblock; if an uncorrectable problem is found it + * generates a suitable message, deallocates the directory clusters, + * and returns the corresponding error code. + * + * if the clustersize argument is non-zero, it is checked against the + * fdcm. otherwise, the clustersize found in the first fdcm is used. + * (the latter applies to gfd/mfd, for which the clustersize is stored + * nowhere else.) + */ +static retcode cleandir (word dcn, int clu, + byte *buf, byte *map, + byte proj, byte prog) +{ + fdcm *m; + fdcm *first; + int i, j, ent, dirblks; + retcode st, ret = ok; + mfdlabel *l; + word16 id; + + /* figure out what we're cleaning */ + if (prog == 255) + { + if (proj == 255) + { + id = MFD; + strcpy (curdir, "[*,*]"); + } + else + { + id = GFD; + sprintf (curdir, "[%d,*]", proj); + } + } + else + { + id = UFD; + sprintf (curdir, "[%d,%d]", proj, prog); + } + curproj = proj; + curprog = prog; + printf ("\rprocessing %s ", curdir); + fflush (stdout); + + if (dcntopcn (dcn) >= pcns) + { + printf ("\nstarting dcn %d for %s out of range\n", + dcn, curdir); + return range; + } + memset (map, 0, dirmapsize); + readdir (dcn, buf); + m = (fdcm *) (buf + 0760); + if (clu == 0) clu = m->uclus; + if (m->uclus != clu || + clu > 16 || + (clu < 4 && id != UFD) || + (pcs <= 16 && clu < pcs) || + (pcs > 16 && clu != 16) || + (clu & (-clu)) != clu) + { + printf ("\ninvalid clustersize %d for %s\n", clu, curdir); + return other; + } + if (m->uent[0] != dcn) + { + printf ("\nstarting dcn %d for %s doesn't match that in cluster map\n", + dcn, curdir); + return other; + } + + /* in old disk, [1,1] label is pack label, don't touch + * otherwise do some checks and fixups. + */ + if (plevel != RDS0 || proj != 1 || prog != 1) + { + l = (mfdlabel *) buf; + if (l->lppn[1] != proj || l->lppn[0] != prog) + { + l->lppn[1] = proj; + l->lppn[0] = prog; + MARK (map); + if (sw.verbose != NULL) + printf ("\nfixed ppn in directory label for %s\n", + curdir); + } + if (l->lid != id) + { + l->lid = id; + MARK (map); + if (sw.verbose != NULL) + printf ("\nfixed identifier field in directory label for %s\n", + curdir); + } + if (l->fill2 != -1 || (l->fill1 & ul_use) == 0) + { + l->fill1 |= ul_use; + l->fill2 = -1; + MARK (map); + if (sw.debug != NULL) + printf ("\nfixed reserved field in directory label for %s\n", + curdir); + } + } + + /* go check the fdcm's in detail */ + if (id == UFD) i = 0; + else i = fd_new; + if (m->uflag != i) + { + m->uflag = i; + MARK (map); + if (sw.verbose != NULL) + printf ("\nfixed directory type flag bit in cluster map for %s\n", + curdir); + } + ent = 0; + /* look for holes in cluster map */ + for (i = 6; i >= 0; i--) + { + if (m->uent[i] == 0) + { + if (ent != 0) + { + printf ("\nholes in cluster map for %s\n", + curdir); + return other; + } + } + else if (dcntopcn (m->uent[i]) >= pcns) + { + printf ("\ncluster %d out of range in cluster map for %s\n", + m->uent[i], curdir); + return range; + } + else + ent = i; + } + if (ent == 0 && m->uent[0] == 0) + { + printf ("\ndirectory %s is empty\n", curdir); + return other; + } + dirblks = ent * clu; /* count of used directory blocks */ + first = m; /* save copy to first fdcm */ + ent = -1; /* no map mismatches yet */ + for (i = 1; i < dirblks; i++) + { + m = (fdcm *) (buf + (i * BLKSIZE) + 0760); + if (memcmp (first, m, sizeof (fdcm)) == 0) continue; + if (first->uclus != m->uclus) + { + printf ("\ninconsistent cluster sizes in maps for %s\n", + curdir); + return other; + } + if (first->uflag != m->uflag) + { + m->uflag = first->uflag; /* fix this quietly */ + MARK (map); + } + for (j = 0; j < 7; j++) + { + if (first->uent[j] == m->uent[j]) continue; + if (first->uent[j] == 0 && + (ent == j || ent == -1)) + { + ent = j; + continue; + } + printf ("\ninconsistent cluster maps for %s\n", curdir); + return other; + } + } + + /* things look cool, go mark the directory as allocated */ + for (i = 0; i < 7; i++) + { + if (first->uent[i] == 0) break; + st = alloc (first->uent[i], clu); + switch (st) + { + case ok: + continue; + case badblock: + printf ("\nbad block"); + ret = badblock; + break; + case dup: + printf ("\ndoubly allocated block"); + break; + case align: + printf ("\nmisaligned cluster"); + break; + case range: + printf ("\ncluster number out of range"); + break; + default: rabort (INTERNAL); + } + printf (", dcn %d in directory %s\n", first->uent[i], curdir); + if (st != badblock) /* bad blk is warning, others quit */ + { + while (i > 0) dealloc (first->uent[--i], clu); + return st; + } + } + return ret; +} + +/* finish up cleaning a directory + * this wipes out any unallocated blockettes. + */ +static void finishdir (byte *buf, byte *map) +{ + lword32 *l; + lword32 or; + int clu, blk, off; + fdcm *m; + byte *p; + byte bit; + mfdlabel *lb; + int ufd; + + /* figure out what we're cleaning */ + lb = (mfdlabel *) buf; + if (lb->lppn[0] == 255) + { + ufd = 0; + if (lb->lppn[1] == 255) + strcpy (curdir, "[*,*]"); + else sprintf (curdir, "[%d,*]", lb->lppn[1]); + } + else + { + ufd = 1; + sprintf (curdir, "[%d,%d]", lb->lppn[1], lb->lppn[0]); + } + m = (fdcm *) (buf + 0760); + l = (lword32 *) buf; + p = map; + bit = 1; + for (clu = 0; clu < 7; clu++) + { + if (m->uent[clu] == 0) break; + for (blk = 0; blk < m->uclus; blk++) + for (off = 0; off < BLKSIZE; off += sizeof (gfdne)) + { + /* check if it's a special spot */ + if (off == 0760 || + (!ufd && (clu == 0 && + (blk == 1 || blk == 2))) || + (off == 0 && clu == 0 && blk == 0)) + { + l += 4; + } + else if ((*p & bit) != 0) /* in use */ + { + if (*(byte *) l & ul_cln) + { + *(byte *) l &= ~ul_cln; + MARK (map); + if (sw.debug != NULL) + printf ("\ncleared ul.cln bit in %s at %d, %d, %d\n", + curdir, clu, blk, off); + } + l += 4; + } + else + { + or = l[0] | l[1] | l[2] | l[3]; + if (or) + { + *l++ = 0; + *l++ = 0; + *l++ = 0; + *l++ = 0; + if (sw.debug != NULL) + printf ("\ncleaned up free entry in %s at %d, %d, %d\n", + curdir, clu, blk, off); + MARK (map); + } + else + { + l += 4; + } + } + if (bit == 0x80) + { + p++; + bit = 1; + } + else bit <<= 1; + continue; + } + } + /* if directory needs writing, write it */ + if (*map & 1) + { + printf ("\rwriting %s ", curdir); + fflush (stdout); + writedir (buf); + } +} + +/* deallocate a directory (used when we zero it) */ +static void deallocdir (byte *buf) +{ + int i; + fdcm *m; + + m = (fdcm *) (buf + 0760); + for (i = 0; i < 7; i++) + { + if (m->uent[i]) + dealloc (m->uent[i], m->uclus); + else break; + } +} + +/* process a file. + * + * returns "ok" if things worked, something else if not. an appropriate + * message is printed if necessary. if the status code is "delete", the + * caller should just delete the file; otherwise, ask first. + * + * note: UFD entries in [1,1] for old disks don't come here. also: the + * caller has to validate the n.e. link and allocate the n.e. + */ +static retcode cleanfile (ufdne *n, byte *buf, byte *map) +{ + retcode st, ret = ok; + ufdae *a; + ufdre *r; + ufdlabel *l; + int clu, i, clurat, sysfile; + int hole = 0, badflag = 0, contig = 1, prevdcn = 0; + word prev; + char name[11]; + long dfsize; /* file size currently in dir */ + + memset (name, 0, sizeof (name)); + init = satt = badb = 0; /* not one of the special files */ + filesize = 0; + r50filename (n->unam, name, 0); + sprintf (curfile, "%s%s", curdir, name); + if (curproj == 0 && curprog == 1) + { + badb = (strcmp (name, "badb.sys") == 0); + satt = (strcmp (name, "satt.sys") == 0); + init = (strcmp (name, "init.sys") == 0); + } + sysfile = badb || init || satt || (n->ustat & us_nok); + printf ("\rprocessing %s ", curfile); + if (n->ustat & us_del) /* marked for delete */ + { + if (sw.verbose != NULL) + printf ("\nfile %s is marked for delete\n", curfile); + return delete; + } + if (n->ustat & us_ufd) /* bogus ufd-like entry */ + { + printf ("\nentry for file %s looks like a ufd\n", curfile); + return other; + } + if (n->unam[2] == TMP) /* .rad50 "tmp" */ + { + if (sw.verbose != NULL) + printf ("\nfile %s deleted\n", curfile); + return delete; + } + st = ulk2 (n->uaa, buf); + if (st != ok) + { + printf ("\ninvalid account entry link for file %s\n", curfile); + return badlink; + } + a = (ufdae *) (buf + e); + clu = a->uclus; + if (clu > 256 || + clu < pcs || + (clu & (-clu)) != clu || + (clu != pcs && satt)) /* badb.sys we checked earlier */ + { + printf ("\nbad clustersize %d for file %s\n", clu, curfile); + return other; + } + clurat = clu / dcs; /* dcn delta if contiguous */ + st = allocent (map); + if (st != ok) + { + printf ("\naccount entry for file %s is doubly allocated\n", + curfile); + return st; + } + if ((a->ulnk & ul_use) == 0) + { + if (sw.debug != NULL) + printf ("\nfixed link from account entry of file %s\n", + curfile); + a->ulnk |= ul_use; + MARK (map); + } + prev = allocchain (a->ulnk, buf, map, ul_use); + if (prev != 0) + { + printf (" in attributes chain for file %s -- will be truncated", + curfile); + if (sysfile) rabort (BADPAK); + if (prev == 1) + a->ulnk = (a->ulnk & ~LINKBITS) | ul_use; + else + { + ulk2 (prev, buf); + *(word16 *) (buf + e) &= ~LINKBITS; + } + MARK (map); + } + prev = allocchain (n->uar, buf, map, 0); + if (prev != 0) + { + printf (" in retrieval entry chain for file %s\n", curfile); + if (sysfile) rabort (BADPAK); + printf ("file will be truncated"); + if (prev == 1) n->uar = 0; + else + { + ulk2 (prev, buf); + *(word16 *) (buf + e) = 0; + } + MARK (map); + } + /* we've allocated all the blockettes, now walk the r.e. chain + * again to allocate the clusters and accumulate the file size + */ + st = ulk2 (n->uar, buf); + while (st != nullink) + { + if (st != ok) rabort (INTERNAL); + r = (ufdre *) (buf + e); + if (prevdcn == 0) prevdcn = r->uent[0] - clurat; + for (i = 0; i < 7; i++) + { + if (r->uent[i] == 0) break; + if (contig) + { + contig = (prevdcn + clurat == r->uent[i]); + prevdcn = r->uent[i]; + } + if (badb || (n->ustat & us_out)) + st = ok; + else st = alloc (r->uent[i], clu); + switch (st) + { + case ok: + filesize += clu; + continue; + case badblock: + if (!badflag) + { + printf ("\nbad block in file %s, cluster %d (block %ld of the file)\n", + curfile, r->uent[i], + filesize + 1); + if (!sysfile) + { + printf ("do you want it truncated (if not, it will be flagged)? "); + if (yesno () == ok) break; + } + badflag = 1; + } + filesize += clu; + continue; + case dup: + printf ("\ndoubly allocated block"); + break; + case align: + printf ("\nmisaligned cluster"); + break; + case range: + printf ("\ncluster number out of range"); + break; + default: + rabort (INTERNAL); + } + printf (", dcn %d in file %s", r->uent[i], curfile); + if (sysfile) rabort (BADPAK); + printf (" -- file will be truncated\n"); + while (i < 7) r->uent[i++] = 0; + r->ulnk = 0; + break; + } + if (i < 7) /* if we stopped on eof */ + { + for ( ; i < 7; i++) + { + hole |= r->uent[i]; + r->uent[i] = 0; + } + hole |= (r->ulnk & LINKBITS); + if (hole != 0) + { + printf ("\nholes in retrieval entry for %s", + curfile); + if (sysfile) printf ("\n"); + else + { + printf (" fixed"); + r->ulnk = 0; + MARK (map); + } + } + } + st = ulk2 (r->ulnk, buf); + } + dfsize = a->usiz; /* pick up current size */ + if (a->urts[0] == 0) /* possible large file */ + dfsize += a->urts[1] << 16; + if (satt) /* satt.sys gets a few checks more */ + { + if (!contig) + { + printf ("\n[0,1]satt.sys is not contiguous\n"); + rabort (BADPAK); + } + if (filesize * BLKSIZE * 8 < pcns) + { + printf ("\n[0,1]satt.sys is too small\n"); + rabort (BADPAK); + } + } + if (!badb && ((n->ustat & us_out) == 0)) + { + if (filesize != ((dfsize + clu - 1) & (-clu))) + { + printf ("\nfile %s size %ld is incorrect (%ld) in ufd", + curfile, filesize, dfsize); + if (sysfile && !satt) printf ("\n"); + else + { + printf (" -- fixed"); + a->usiz = filesize; + if (filesize >> 16) + { + a->urts[0] = 0; + a->urts[1] = filesize >> 16; + } + else if (a->urts[0] == 0) a->urts[1] = 0; + MARK (map); + } + } + } + if (badflag) + { + if ((a->ulnk & ul_bad) == 0) + { + a->ulnk |= ul_bad; + MARK (map); + } + } + else if (a->ulnk & ul_bad) + { + a->ulnk &= ~ul_bad; + MARK (map); + } + if (!contig && (n->ustat & us_nox)) + { + printf ("\nfile %s is marked as contiguous but is not\n", + curfile); + n->ustat &= ~us_nox; + MARK (map); + } + if (n->ustat & (us_wrt | us_upd)) + { + if (sw.debug != NULL) + printf ("\ncleared write/update flags for file %s\n", + curfile); + n->ustat &= ~(us_wrt | us_upd); + MARK (map); + } + if ((filesize >> 16) != 0 && (n->uprot & up_run) != 0) + { + if (sw.debug != NULL) + printf ("\ncleared runnable bit for file %s\n", + curfile); + n->uprot &= ~up_run; + MARK (map); + } + if ((n->uaa & ~(LINKBITS | ul_che)) != 0 || + (n->uar & ~LINKBITS) != 0 || + (n->ulnk & ~(LINKBITS | ul_che)) != 0) + { + if (sw.debug != NULL) + printf ("\nfixed links in n.e. for file %s\n", + curfile); + n->uaa &= LINKBITS | ul_che; + n->uar &= LINKBITS; + n->ulnk &= LINKBITS | ul_che; + MARK (map); + } + return ok; +} + +/* process the content of a ufd. this is separate from cleanufd so + * we can call it for the MFD [1,1] of an RDS0 disk. + * the buf and map pointers point to where the data and blockette maps + * are, normally ufdbuf and ufdmap but mfdbuf and mfdmap for the + * special case. + */ +static void processufd (byte *buf, byte *map) +{ + word prev, link; + retcode st; + ufdlabel *l; + ufdne *n; + + l = (ufdlabel *) buf; + link = l->ulnk; + prev = 1; + for (;;) + { + st = ulk2 (link, buf); + if (st == nullink) break; /* all done */ + if (st == ok) + st = allocent (map); /* allocate n.e. */ + if (st != ok) /* link bad or duplicate */ + { + if (prev == 1) + { + printf ("\nbad link in label of %s", curdir); + printf (" -- UFD will be zeroed"); + yes (); /* ask for permission */ + l->ulnk = 0; + } + else + { + printf ("\nbad next file link in file %s" + " -- remaining files will be lost", + curfile); + yes (); /* ask for permission */ + ulk2 (prev, buf); + n = (ufdne *) (buf + e); + n->ulnk = 0; + } + MARK (map); + break; + } + n = (ufdne *) (buf + e); + st = cleanfile (n, buf, map); + if (st != ok) + { + if (st != delete) + { + if (satt || init || badb || + (n->ustat & us_nok)) + { + printf ("\nfile %s cannot be deleted\n", + curfile); + rabort (BADPAK); + } + yes (); /* ask for ok */ + } + link = n->ulnk; /* set next file */ + if (prev == 1) l->ulnk = link; + else + { + ulk2 (prev, buf); + n = (ufdne *) (buf + e); + n->ulnk = link; + } + } + else + { + files++; + dirfiles++; + dirtsize += filesize; + prev = link; + link = n->ulnk; + } + } +} + +/* go clean a ufd */ +static retcode cleanufd (word dcn, int proj, int prog) +{ + retcode st, ret = ok; + word prev; + + dirfiles = dirtsize = 0; + if (dcn == 0) return 0; /* nothing there... */ + st = cleandir (dcn, 0, ufdbuf, ufdmap, proj, prog); + if (st != ok) + { + if (st != badblock) return st; + if (proj == 0 && prog == 1) + { + printf ("\nclean will continue, but there may be problems\n"); + yes (); /* get approval */ + } + else + { + printf ("\ncontinue cleaning [%d,%d] anyway? ", + proj, prog); + if (yesno () != ok) + { + deallocdir (ufdbuf); + return other; + } + } + ret = st; + } + + /* go process the ufd contents */ + processufd (ufdbuf, ufdmap); + finishdir (ufdbuf, ufdmap); + ufds++; + return ret; /* success */ +} + +/* go clean a gfd */ +static int cleangfd (word dcn, retcode proj) +{ + int prog; + retcode st, ret = ok; + word prev; + word16 *dcnp, *unep; + gfdne *n; + gfdae *a; + uattr *at; + ua_quo *q; + + if (dcn == 0) return 0; /* nothing there... */ + st = cleandir (dcn, 0, gfdbuf, gfdmap, proj, 255); + if (st != ok) + { + if (st != badblock) return st; + if (proj == 0) + { + printf ("\nclean will continue, but there may be problems\n"); + yes (); /* get approval */ + } + else + { + printf ("\ncontinue cleaning [%d,*] anyway? ", proj); + if (yesno () != ok) + { + deallocdir (gfdbuf); + return other; + } + } + ret = st; + } + + /* check that there isn't an entry for user 255 */ + if (*(word16 *) (gfdbuf + 01776) != 0 || + *(word16 *) (gfdbuf + 02776) != 0) + { + printf ("\ninvalid user [%d,255] found in gfd -- deleted\n", + proj); + *(word16 *) (gfdbuf + 01776) = 0; + *(word16 *) (gfdbuf + 02776) = 0; + MARK (gfdmap); + } + + /* check that there isn't an entry for [0,0] either */ + if (proj == 0 && + (*(word16 *) (gfdbuf + 01000) != 0 || + *(word16 *) (gfdbuf + 02000) != 0)) + { + printf ("\ninvalid user [0,0] found in gfd [0,*] -- deleted\n"); + *(word16 *) (gfdbuf + 01000) = 0; + *(word16 *) (gfdbuf + 02000) = 0; + MARK (gfdmap); + } + + /* now process each user */ + for (prog = 0; prog < 255; prog++) + { + dcnp = (word16 *) (gfdbuf + 01000 + (2 * prog)); + unep = (word16 *) (gfdbuf + 02000 + (2 * prog)); + if (*unep & ~LINKBITS) + { + if (sw.debug != NULL) + printf ("\nname entry link for [%d,%d] fixed\n", + proj, prog); + *unep &= LINKBITS; + MARK (gfdmap); + } + st = ulk2 (*unep, gfdbuf); + if (st == nullink) /* no n.e. link */ + { + if (*dcnp != 0) + { + *dcnp = 0; + MARK (gfdmap); + printf ("\ndcn pointer for non-existent account [%d,%d zeroed\n", + proj, prog); + } + continue; + } + if (st) /* bad link! */ + { + printf ("\nname entry link for [%d,%d] is bad\n", + proj, prog); + if (proj == 0 && prog == 1) rabort (BADPAK); + printf ("account will be deleted\n"); + yes (); /* get approval */ + *unep = 0; + *dcnp = 0; + MARK (gfdmap); + continue; + } + n = (gfdne *) (gfdbuf + e); + if (n->ustat & us_del) /* account marked for delete */ + { + if (sw.verbose != NULL || + (proj == 0 & prog == 1)) + printf ("\naccount [%d,%d] marked for delete\n", + proj, prog); + if (proj == 0 && prog == 1) rabort (BADPAK); + *unep = 0; /* so delete it... */ + *dcnp = 0; + MARK (gfdmap); + continue; + } + if ((n->ustat & us_ufd) == 0) /* not marked as ufd! */ + { + printf ("\nname entry for [%d,%d] not marked as ufd\n", + proj, prog); + if (proj == 0 && prog == 1) rabort (BADPAK); + printf ("account will be deleted\n"); + yes (); /* get approval */ + *unep = 0; + *dcnp = 0; + MARK (gfdmap); + continue; + } + if (n->unam[0] != ((proj << 8) | prog)) + { + printf ("\nname entry for [%d,%d] has wrong ppn [%d,%d]\n", + proj, prog, + n->unam[0] >> 8, n->unam[0] & 0xff); + if (proj == 0 && prog == 1) rabort (BADPAK); + *unep = 0; /* so delete it... */ + *dcnp = 0; + MARK (gfdmap); + continue; + } + allocent (gfdmap); /* allocate name entry */ + st = ulk2 (n->uaa, gfdbuf); + if (st != ok) /* something wrong with a.e. */ + { + printf ("\naccount entry link for [%d,%d] is bad\n", + proj, prog); + if (proj == 0 && prog == 1) rabort (BADPAK); + printf ("account will be deleted\n"); + yes (); /* get approval */ + ulk2 (*unep, gfdbuf); /* mark n.e. free */ + deallocent (gfdmap); + *unep = 0; + *dcnp = 0; + MARK (gfdmap); + continue; + } + a = (gfdae *) (gfdbuf + e); + if (NULLINK (a->ulnk)) + { + if (a->ulnk != ul_use) + { + if (sw.debug != NULL) + printf ("\nlink from account entry for [%d,%d] fixed\n", + proj, prog); + a->ulnk = ul_use; + MARK (gfdmap); + } + } + else + { + printf ("\nlink from account entry for [%d,%d] cleared\n", + proj, prog); + a->ulnk = ul_use; + MARK (gfdmap); + } + allocent (gfdmap); /* allocate acct. entry */ + q = NULL; /* assume no quota block */ + if (plevel == RDS12 && (proj != 0 || prog != 1)) + { + st = ulk2 (n->ulnk, gfdbuf); /* get attributes */ + while (st == ok) + { + at = (uattr *) (gfdbuf + e); + if (at->uatyp == aa_quo) + { + q = (ua_quo *) at; + break; + } + st = ulk2 (at->ulnk, gfdbuf); + } + if (q == NULL) + { + printf ("\nquota block missing for [%d,%d]\n" + "account will be deleted\n", + proj, prog); + yes (); /* get approval */ + ulk2 (n->uaa, gfdbuf); /* mark a.e. free */ + deallocent (gfdmap); + ulk2 (*unep, gfdbuf); /* mark n.e. free */ + deallocent (gfdmap); + *unep = 0; + *dcnp = 0; + MARK (gfdmap); + continue; + } + } + prev = allocchain (n->ulnk, gfdbuf, gfdmap, 0); + if (prev) + { + /* note that the problem is after the quota block, + * for cases where we need one. that's because + * the quota block scan is before this point. + */ + printf (" in account [%d,%d] attribute chain -- will be truncated\n", + proj, prog); + yes (); /* get approval */ + if (prev == 1) n->ulnk = 0; + else + { + ulk2 (prev, gfdbuf); + *(word16 *) (gfdbuf + e) = ul_use; + } + MARK (gfdmap); + } + if (*dcnp != n->uar) /* inicln doesn't do this... */ + { + n->uar = *dcnp; + MARK (gfdmap); + if (sw.verbose != NULL) + printf ("\nfixed account [%d,%d] dcn in n.e.\n", + proj, prog); + } + st = cleanufd (*dcnp, proj, prog); + if (st == badblock) /* bad block but it worked */ + { + a->ulnk |= ul_bad; /* mark bad block in account */ + MARK (gfdmap); + } + else if (st != ok) + { + if (proj == 0 && prog == 1) rabort (BADPAK); + printf ("\naccount [%d,%d] will be zeroed\n", + proj, prog); + yes (); /* get approval */ + *dcnp = 0; + MARK (gfdmap); + } + if ((st == ok || st == badblock) && q != NULL) + { + if (((q->aq_crm << 16) | q->aq_crl) != dirtsize) + { + if (sw.debug != NULL) + printf ("\naccount [%d,%d] usage fixed, was %d now %ld\n", + proj, prog, + ((q->aq_crm << 16) | q->aq_crl), + dirtsize); + q->aq_crm = dirtsize >> 16; + q->aq_crl = dirtsize & 0xffff; + MARK (gfdmap); + } + } + if (sw.verbose != NULL) + printf ("\ntotal of %ld files, %ld blocks in [%d,%d]\n", + dirfiles, dirtsize, proj, prog); + } + finishdir (gfdbuf, gfdmap); + gfds++; + return ret; /* success */ +} + +/* go clean the mfd for a new format (RDS1.1 or above) disk */ +static void cleannewmfd (void) +{ + int proj; + retcode st; + word prev; + mfdlabel *l; + word16 *dcnp, *attrp; + + st = cleandir (mfddcn, 0, mfdbuf, mfdmap, 255, 255); + if (st != ok) + { + if (st != badblock) rabort (BADPAK); + printf ("\nclean will continue, but there may be problems\n"); + yes (); /* get approval */ + } + l = (mfdlabel *) mfdbuf; + + /* allocate any mfd attributes */ + prev = allocchain (l->malnk, mfdbuf, mfdmap, 0); + if (prev) + { + printf (" in mfd attribute chain -- will be truncated\n"); + yes (); /* get approval */ + if (prev == 1) l->malnk = 0; + else + { + ulk2 (prev, mfdbuf); + *(word16 *) (mfdbuf + e) = ul_use; + } + MARK (mfdmap); + } + + /* check that there isn't an entry for group 255 */ + if (*(word16 *) (mfdbuf + 01776) != 0 || + *(word16 *) (mfdbuf + 02776) != 0) + { + printf ("\ninvalid group [255,*] found in mfd -- deleted\n"); + *(word16 *) (mfdbuf + 01776) = 0; + *(word16 *) (mfdbuf + 02776) = 0; + MARK (mfdmap); + } + + /* now process each group */ + for (proj = 0; proj < 255; proj++) + { + dcnp = (word16 *) (mfdbuf + 01000 + (2 * proj)); + attrp = (word16 *) (mfdbuf + 02000 + (2 * proj)); + if (*attrp & ~LINKBITS) + { + if (sw.debug != NULL) + printf ("\nattribute link for group %d fixed\n", + proj); + *attrp &= LINKBITS; + MARK (mfdmap); + } + prev = allocchain (*attrp, mfdbuf, mfdmap, 0); + if (prev) + { + yes (); /* get approval */ + printf (" in group [%d,*] attribute chain -- will be truncated\n", + proj); + if (prev == 1) *attrp = 0; + else + { + ulk2 (prev, mfdbuf); + *(word16 *) (mfdbuf + e) = ul_use; + } + MARK (mfdmap); + } + st = cleangfd (*dcnp, proj); + if (st != ok && st != badblock) + { + if (proj == 0) rabort (BADPAK); + printf ("\ngfd [%d,*] will be zeroed\n", proj); + yes (); /* get approval */ + *dcnp = 0; + MARK (mfdmap); + } + } + finishdir (mfdbuf, mfdmap); +} + +/* go clean the mfd for an old format (RDS0) disk */ +static void cleanoldmfd (void) +{ + retcode ret; + + ret = cleandir (mfddcn, 0, mfdbuf, mfdmap, 1, 1); + if (sw.debug != NULL) + printf ("\ncleandir returned %d\n", ret); + finishdir (mfdbuf, mfdmap); +} + +/* set up the bitmap of bad clusters + * note that these are not marked (for the moment) in sattbf2 so they + * don't appear as double allocations if a file contains a bad block. + * instead, we check for the bad block map separately. + */ +static void allocbadb (void) +{ + firqb f; + ufdre *r; + ufdae *a; + int i, clurat, fsize = 0; + retcode st; + word link, dcn; + word16 *prevlink; + + memset (badbmap, 0, sattsize); /* initially no bad blocks */ + if (!findfile (&f, "[0,1]badb.sys")) + { + printf ("\n[0,1]badb.sys is missing!\n"); + rabort (BADPAK); + } + if (f.clusiz != pcs) + { + printf ("\n[0,1]badb.sys clustersize is invalid (%d should be %d)", + f.clusiz, pcs); + rabort (BADPAK); + } + clurat = pcs / dcs; + link = f.rlink; + readlk (f.nlink); + prevlink = &(use (ufdne, k)->uar); /* in case link is bad */ + for (;;) + { + st = readlkchk (link); + if (st == nullink) break; /* null link */ + else if (st != ok) + { + printf ("\nbad link in [0,1]badb.sys -- truncated\n"); + if (sw.prot == NULL) + { + *prevlink = 0; + fbwrite (); + } + break; + } + r = use (ufdre, k); + for (i = 0; i < 7; i++) + { + dcn = r->uent[i]; + if (dcn == 0) break; + fsize += pcs; /* accumulate badb.sys size */ + if (dcn % clurat) /* check for PCS boundary */ + { + printf ("\nwarning, [0,1]badb.sys dcn %d not on PCS boundary\n", dcn); + dcn = dcn / clurat * clurat; + } + st = alloc (dcn, pcs); + if (st == 3) + { + printf ("\nwarning, [0,1]badb.sys dcn %d is too large\n", dcn); + } + else if (st) + { + printf ("\nwarning, [0,1]badb.sys dcn %d doubly allocated\n", dcn); + } + } + prevlink = &(r->ulnk); + link = r->ulnk; + } + readlk (f.alink); + a = use (ufdae, k); + if (a->usiz != fsize) + { + if (sw.prot == NULL) + { + a->usiz = fsize; + fbwrite (); + if (sw.verbose != NULL) + printf ("\n[0,1]badb.sys filesize fixed\n"); + } + else printf ("\nnote: [0,1]badb.sys filesize doesn't match r.e. chain\n"); + } + memcpy (badbmap, sattbf2, sattsize); /* load the bad block map */ + memset (sattbf2, 0xff, sattsize); /* and make all free again */ + memset (sattbf2, 0, pcns / 8); + if (pcns & 7) sattbf2[pcns / 8] = 0xff << (pcns & 7); + if (sw.verbose != NULL) + printf ("total of %d bad blocks\n", fsize); +} + +/* validate the pack label, fix up any inconsistencies, and mark the + * pack as mounted in case we get a failure in mid-operation. + */ +static void cleanlabel (void) +{ + packlabel *p; + + readdcn (1); /* get pack label */ + p = use(packlabel,0); + if (p->fill1 != -1) + { + if (sw.debug != NULL) + printf ("pack label reserved field fixed\n"); + p->fill1 = -1; + } + if (pflags & uc_new) /* "new" flag set */ + { + if (alloc (1, pcs)) /* mark pack label allocated */ + rabort (INTERNAL); + if (plevel < RDS11) + { + p->plvl = plevel = RDS11; + if (sw.verbose != NULL) + printf ("pack rev level field fixed\n"); + } + else if (plevel > RDS12) + { + printf ("unsupported structure level %d.%d\n", + plevel >> 8, plevel & 0xff); + rabort (NOMSG); + } + } + else /* old pack */ + { + if (p->plvl) + { + p->plvl = 0; + if (sw.verbose != NULL) + printf ("pack label rev level field cleared\n"); + } + if (p->mdcn) + { + p->mdcn = 0; + if (sw.verbose != NULL) + printf ("pack label mfd cluster field cleared\n"); + } + } + /* while we're here, mark the pack as mounted in case of trouble + * (and, for that matter, so the rumountrw() call will work) + */ + if (sw.prot == NULL) + { + p->pstat |= uc_mnt; + fbwrite (); + } + else fiblk = -1; /* readonly clean, invalidate buffer */ +} + +/* switches recognized: + * -Debug lots of debug info + * -verbose print more info about what's happening + * -protect don't write anything, just inspect the disk + */ +void doclean (int argc, char **argv) +{ + int i, flag; + byte *o, *n; + byte m; + + if (sw.prot == NULL) + ropen (DWRITEMODE); /* open it first */ + else ropen (DREADMODE); + readlabel (); /* read and remember label data */ + if (pcs < dcs || pcs > 64 || (pcs > 16 && plevel < RDS12) || + (pcs & -pcs) != pcs) + { + printf ("invalid pack cluster size %d\n", pcs); + rabort (BADPAK); + } + if (sw.verbose != NULL) + { + if (pflags & uc_mnt) printf ("disk needs rebuilding.\n"); + else printf ("disk not marked as needing rebuilding.\n"); + } + if ((pflags & uc_ro) && + sw.overwrite == NULL && + sw.prot == NULL) + rabort (ROPACK); + sattsize = 0; /* SATT not looked up yet */ + womsat = FALSE; /* and SATT is clean */ + fiblkw = FALSE; /* FIBUF ditto */ + findsat (); /* make sure we know where satt is */ + + /* allocate some buffers we need */ + if (sattbf2 != NULL) free (sattbf2); + if ((sattbf2 = (byte *) malloc (sattsize)) == NULL) rabort (NOMEM); + if (badbmap != NULL) free (badbmap); + if ((badbmap = (byte *) malloc (sattsize)) == NULL) rabort (NOMEM); + if (mfdbuf != NULL) free (mfdbuf); + if ((mfdbuf = (byte *) malloc (dirbufsize)) == NULL) rabort (NOMEM); + if (mfdmap != NULL) free (mfdmap); + if ((mfdmap = (byte *) malloc (dirmapsize)) == NULL) rabort (NOMEM); + if (gfdbuf != NULL) free (gfdbuf); + if ((gfdbuf = (byte *) malloc (dirbufsize)) == NULL) rabort (NOMEM); + if (gfdmap != NULL) free (gfdmap); + if ((gfdmap = (byte *) malloc (dirmapsize)) == NULL) rabort (NOMEM); + if (ufdbuf != NULL) free (ufdbuf); + if ((ufdbuf = (byte *) malloc (dirbufsize)) == NULL) rabort (NOMEM); + if (ufdmap != NULL) free (ufdmap); + if ((ufdmap = (byte *) malloc (dirmapsize)) == NULL) rabort (NOMEM); + + /* init stats */ + gfds = ufds = files = clusters = 0; + + /* start out with nothing allocated */ + memset (sattbf2, 0xff, sattsize); + memset (sattbf2, 0, pcns / 8); + if (pcns & 7) sattbf2[pcns / 8] = 0xff << (pcns & 7); + + /* set up the bad block map */ + allocbadb (); + if (badbmap[0] & 1) + { + printf ("pack cluster 1 (pack label) is marked as bad\n"); + rabort (BADPAK); + } + + /* process the pack label */ + cleanlabel (); + + /* now do the rest of the file structure */ + if (plevel) cleannewmfd (); + else cleanoldmfd (); + + /* merge bad block map into satt */ + for (i = 0; i < sattsize; i++) sattbf2[i] |= badbmap[i]; + + /* all done. see if anything changed */ + if (memcmp (sattbufp, sattbf2, sattsize) != 0) + { + if (sw.verbose != NULL) + { + flag = 0; + m = 1; + o = sattbufp; + n = sattbf2; + for (i = 0; i < pcns; i++) + { + if ((*n & m) != 0 && (*o & m) == 0) + { + if (!flag) printf ("was free, now allocated: "); + flag = 1; + printf ("%d ", i); + } + if (m == 0x80) + { + m = 1; + o++; + n++; + } + else m <<= 1; + } + if (flag) printf ("\n"); + flag = 0; + m = 1; + o = sattbufp; + n = sattbf2; + for (i = 0; i < pcns; i++) + { + if ((*n & m) == 0 && (*o & m) != 0) + { + if (!flag) printf ("was allocated, now free: "); + flag = 1; + printf ("%d ", i); + } + if (m == 0x80) + { + m = 1; + o++; + n++; + } + else m <<= 1; + } + if (flag) printf ("\n"); + } + if (sw.prot == NULL) + { + memcpy (sattbufp, sattbf2, sattsize); + MARKS; /* indicate SATT needs writing */ + } + } + if (sw.verbose != NULL) + printf ("\n%ld gfds, %ld ufds, %ld files, %ld clusters processed\n", + gfds, ufds, files, clusters); + else + printf ("\n"); + + if (sw.prot == NULL) + rumountrw (); /* write satt, mark clean, and close */ + else rumount (); +} + diff --git a/extracters/rstsflx/doclean.h b/extracters/rstsflx/doclean.h new file mode 100644 index 0000000..d700748 --- /dev/null +++ b/extracters/rstsflx/doclean.h @@ -0,0 +1 @@ +extern void doclean (int argc , char ** argv); diff --git a/extracters/rstsflx/docomp.c b/extracters/rstsflx/docomp.c new file mode 100644 index 0000000..362c4f5 --- /dev/null +++ b/extracters/rstsflx/docomp.c @@ -0,0 +1,62 @@ +/* handler for the "compress" command */ + +#include +#include + +#include "flx.h" +#include "fldef.h" +#include "docomp.h" +#include "diskio.h" +#include "fip.h" + +void docomp (int argc, char **argv) /* zero unused clusters */ +{ + byte *s; + int bit, szb; + long first, size, iosize; + long n; + + rmountrw (); /* mount the disk R/W */ + memset (iobuf, 0, iobufsize); /* clear out I/O buffer */ + s = sattbufp; + szb = (diskblocks - dcs) / pcs; /* satt bits actually used */ + bit = 1; + n = 0; /* start looking at PCN = 0 */ + for (;;) { + for ( ; n < szb; n++) { /* scan past allocated clusters */ + if (bit > 0x80) { + bit = 1; + s++; + } + if ((*s & bit) == 0) break; + bit <<= 1; + } + if (n == szb) break; + first = n; + for ( ; n < szb; n++) { /* find length of free area */ + if (bit > 0x80) { + bit = 1; + s++; + } + if (*s & bit) break; + bit <<= 1; + } + size = (n - first) * pcs; + first = pcntolbn(first); /* get starting lbn */ + if (sw.verbose != NULL) { + printf ("clearing %ld..%ld\015", first, first + size - 1); + fflush (stdout); + } + for (;;) { + iosize = size * BLKSIZE; + if (iosize > iobufsize) iosize = iobufsize; + rwrite (first, iosize, iobuf); + size -= iobufsize / BLKSIZE; + if (size <= 0) break; + first += iobufsize / BLKSIZE; + } + } + if (sw.verbose != NULL) printf ("\n"); + rumountrw (); /* done with the disk */ +} + diff --git a/extracters/rstsflx/docomp.h b/extracters/rstsflx/docomp.h new file mode 100644 index 0000000..e6990e2 --- /dev/null +++ b/extracters/rstsflx/docomp.h @@ -0,0 +1 @@ +extern void docomp(int argc , char ** argv); diff --git a/extracters/rstsflx/dodelete.c b/extracters/rstsflx/dodelete.c new file mode 100644 index 0000000..a60d1cb --- /dev/null +++ b/extracters/rstsflx/dodelete.c @@ -0,0 +1,28 @@ +/* handler for the "delete" command */ + +#include + +#include "flx.h" +#include "fldef.h" +#include "dodelete.h" +#include "fip.h" +#include "filename.h" +#include "fileio.h" +#include "scancmd.h" + +void dodel2 (firqb *f) +{ + if (protfile (f)) return; /* quit if protected file */ + delfile (f); /* now really delete the file */ + if (sw.verbose != NULL) { + printcurname (f); + printf (" deleted\n"); + } +} + +void dodelete (int argc, char **argv) +{ + rmountrw (); /* mount r/w */ + dofiles (argc, argv, dodel2, NOTNULL); + rumountrw (); /* done with r/w */ +} diff --git a/extracters/rstsflx/dodelete.h b/extracters/rstsflx/dodelete.h new file mode 100644 index 0000000..3440508 --- /dev/null +++ b/extracters/rstsflx/dodelete.h @@ -0,0 +1,4 @@ +extern void dodel2(firqb * f); + /* Prototype include a typedef name. + It should be moved after the typedef declaration */ +extern void dodelete(int argc , char ** argv); diff --git a/extracters/rstsflx/dodir.c b/extracters/rstsflx/dodir.c new file mode 100644 index 0000000..32633ed --- /dev/null +++ b/extracters/rstsflx/dodir.c @@ -0,0 +1,128 @@ +/* handler for the mkdir" and "rmdir" commands */ + +#include +#include +#include + +#include "flx.h" +#include "fldef.h" +#include "dodir.h" +#include "fip.h" +#include "filename.h" + +void domkdir (int argc, char **argv) +{ + int n; + firqb f; + int newclu; + char *p; + word link, ulink, alink, qlink; + uattr *u; + ua_qt2 *q; + + if (argc == 0) { + printf ("Usage: %s mkdir dir...\n", progname); + return; + } + rmountrw (); + if (sw.clusiz == NULL) { + newclu = pcs; + if (newclu > 16) newclu = 16; + } else { + newclu = strtol (sw.clusiz, &p, 10); + if (newclu < 0) { + newclu = -newclu; + if (newclu < pcs) { + newclu = pcs; + if (newclu > 16) newclu = 16; + } + } + if (*p != '\0' || (newclu < pcs && newclu < 16) + || newclu > 16 || + (newclu & (-newclu)) != newclu) { + rumountrw (); /* dismount first */ + printf ("Invalid clustersize %s\n", sw.clusiz); + return; + } + } + for (n = 0; n < argc; n++) { + if (!parse (argv[n], &f) || f.flags != f_ppn) { + printf ("Invalid PPN %s\n", argv[n]); + continue; + } + if (initfilescan (&f, gfdatrtbl)) { + printf ("Directory [%d,%d] already exists\n", + f.cproj, f.cprog); + } else { + f.cproj = f.proj; /* set up for makedir */ + f.cprog = f.prog; + if (makedir (&f, newclu)) { + if (sw.user != NULL) { + fbread (curgfd + gfdatrtbl); + link = fibufw[f.cprog]; + readlktbl (link); + alink = use(gfdne,k)->ulnk; + if ((ulink = getent ()) == 0) + printf ("No room to mark account as user account\n"); + else { + readlk (ulink); + u = use(uattr,k); + u->ulnk = alink; + u->uatyp = aa_pas; + MARKF; + if ((qlink = getent ()) == 0) { + printf ("No room for second quota block\n"); + qlink = ulink; + } else { + readlk (qlink); + q = use(ua_qt2,k); + q->ulnk = ulink; + q->uatyp = aa_qt2; + q->a2_job = 255U; + q->a2_rib = 4; + q->a2_msg = 12; + MARKF; + } + readlk (link); + use(gfdne,k)->ulnk = qlink; + MARKF; + } + } + if (sw.verbose != NULL) + printf ("Account [%d,%d] created\n", + f.proj, f.prog); + } + } + } + rumountrw (); +} + +void dormdir (int argc, char **argv) +{ + int n; + firqb f; + word ne; + + if (argc == 0) { + printf ("Usage: %s rmdir dir...\n", progname); + return; + } + rmountrw (); + for (n = 0; n < argc; n++) { + if (!parse (argv[n], &f) || (f.flags & ~f_ppnw) != f_ppn) { + printf ("Invalid PPN %s\n", argv[n]); + continue; + } + if ((ne = initfilescan (&f, gfdatrtbl)) == 0) { + printf ("No PPNs matching "); + printfqbppn (&f); + continue; + } + do { + if (remdir (&f, ne) && sw.verbose != NULL) + printf ("Account [%d,%d] deleted\n", + f.cproj, f.cprog); + } while ((ne = nextppn (&f, gfdatrtbl)) != 0); + } + rumountrw (); +} diff --git a/extracters/rstsflx/dodir.h b/extracters/rstsflx/dodir.h new file mode 100644 index 0000000..5cd5993 --- /dev/null +++ b/extracters/rstsflx/dodir.h @@ -0,0 +1,2 @@ +extern void domkdir(int argc , char ** argv); +extern void dormdir(int argc , char ** argv); diff --git a/extracters/rstsflx/dodump.c b/extracters/rstsflx/dodump.c new file mode 100644 index 0000000..bb629c1 --- /dev/null +++ b/extracters/rstsflx/dodump.c @@ -0,0 +1,134 @@ +/* handler for the "dump" command */ + +#include +#include +#include + +#include "flx.h" +#include "fldef.h" +#include "dodump.h" +#include "fip.h" +#include "filename.h" +#include "diskio.h" +#include "fileio.h" +#include "scancmd.h" + +long startblk, endblk; + +static byte toprint (byte c) +{ + if (c > 31 && c < 127) return (c); + if (c > 159 ) return (c); + return ('.'); +} + +static void dumpbuf (firqb *f, word16 *buf, long count, long firstbyte) +{ + int b; + long off, block; + char r50[4]; + + for (off = 0; off < count; off += 16, buf += 8) { + if ((off & (BLKSIZE - 1)) == 0) { + block = (firstbyte + off) / BLKSIZE + startblk; + if (f != NULL) { + printf ("\nFile: "); + printcurname (f); + } else printf ("\nRSTS disk"); + printf (" block %ld\n", block); + } + if (sw.hex != NULL) { + printf ("%03lx/ ", off & (BLKSIZE - 1)); + for (b = 0; b < 8; b++) printf ("%04x ", buf[b]); + } else { + printf ("%03lo/ ", off & (BLKSIZE - 1)); + for (b = 0; b < 8; b++) printf ("%06o ", buf[b]); + } + for (b = 0; b < 8; b++) printf ("%c%c", toprint (buf[b] & 0xff), toprint (buf[b] >> 8)); + if (sw.wide != NULL) { + for (b = 0; b < 8; b++) { + r50toascii (buf[b], r50, TRUE); + printf (" %s", r50); + } + } + printf ("\n"); + } +} + +static void dumpfile (firqb *f) +{ + long iocount, totalbytes, end2; + + if (startblk >= f->size) return; /* nothing to do */ + end2 = endblk; + if (end2 > f->size) end2 = f->size; /* get end for this file */ + initrandom (f); /* set up for random read */ + fileseek (f, startblk); /* and seek to start vbn */ + totalbytes = 0; + while (TRUE) { + iocount = (end2 - startblk) * BLKSIZE - totalbytes; + if (iocount > iobufsize) iocount = iobufsize; + if (iocount <= 0) return; + iocount = seqio (f, iocount, rread, iobuf); + if (iocount == 0) return; /* exit if EOF */ + dumpbuf (f, (word16 *) iobuf, iocount, totalbytes); + totalbytes += iocount; + } +} + +static void dumpdisk (void) +{ + long lbn, iocount, totalbytes; + + if (endblk > diskblocks) endblk = diskblocks; + totalbytes = 0; + for (lbn = startblk; lbn < endblk; lbn += iobufsize / BLKSIZE) { + iocount = (endblk - lbn) * BLKSIZE; + if (iocount > iobufsize) iocount = iobufsize; + if (iocount <= 0) return; + rread (lbn, iocount, iobuf); + dumpbuf (NULL, (word16 *) iobuf, iocount, totalbytes); + totalbytes += iocount; + } +} + +/* "dump" will dump the disk NFS, or a directory (UFD), or a file. If no + * name is specified, you get NFS disk. In that case, there need not be + * any meaningful file structure on the disk. If a PPN is specified but no + * file name, you get the UFD; if a filename is given, you get that file. + */ + +void dodump (int argc, char **argv) +{ + char *p; + + if (sw.start == NULL) startblk = 0; /* start at the bottom */ + else { + if (*sw.start == '0') startblk = strtoul (sw.start, &p, 8); + else startblk = strtoul (sw.start, &p, 10); + if (*p != '\0') { + printf ("Invalid start block %s\n", sw.start); + return; + } + } + if (sw.end == NULL) endblk = 1L << 23; /* dump everything */ + else { + if (*sw.end == '0') endblk = strtoul (sw.end, &p, 8); + else endblk = strtoul (sw.end, &p, 10); + if (*p != '\0') { + printf ("Invalid end block %s\n", sw.end); + return; + } + } + endblk++; /* make end + 1 */ + if (argc == 0) { + ropen (DREADMODE); /* open the disk */ + dumpdisk (); /* do NFS dump */ + rclose (); /* now close it */ + } else { + rmount (); /* mount R/O */ + dofiles (argc, argv, dumpfile, NULLISNULL); + rumount (); /* done with the disk */ + } +} + diff --git a/extracters/rstsflx/dodump.h b/extracters/rstsflx/dodump.h new file mode 100644 index 0000000..fb8f1c0 --- /dev/null +++ b/extracters/rstsflx/dodump.h @@ -0,0 +1 @@ +extern void dodump(int argc , char ** argv); diff --git a/extracters/rstsflx/doget.c b/extracters/rstsflx/doget.c new file mode 100644 index 0000000..51cdd3c --- /dev/null +++ b/extracters/rstsflx/doget.c @@ -0,0 +1,193 @@ +/* handler for the "get" command */ + +#include +#include +#include +#include +#include +#if (defined(__MSDOS__) && !defined(__unix__)) +#include +#endif + +#include "flx.h" +#include "fldef.h" +#include "doget.h" +#include "fip.h" +#include "filename.h" +#include "fileio.h" +#include "scancmd.h" + +#ifndef S_IRWXU +#define S_IRWXU (S_IREAD+S_IWRITE+S_IEXEC) +#endif +#ifndef S_IRWXG +#define S_IRWXG 0 +#endif +#ifndef S_IRWXO +#define S_IRWXO 0 +#endif +#ifndef S_ISDIR +#define S_ISDIR(x) (((x) & S_IFMT) == S_IFDIR) +#endif + +#define mkdirmode (S_IRWXU | S_IRWXG | S_IRWXO) /* mode for new directory */ + +static int concat; /* concatenating to one file */ +static struct stat sbuf; +static char *on, *on2; +static FILE *of; +static byte cproj, cprog; +static long matches, tmatches; +static int binmode; /* true if doing binary copy */ +static const char *openmode; +static long filebytes, tbytes; + +static void dogetfile (firqb *f) { + struct stat sbuf2; + char tmpname[FILENAME_MAX]; + char dirname[FILENAME_MAX]; + char rname[NAMELEN]; + + if (!concat) { + if (S_ISDIR(sbuf.st_mode)) { + if (f->stat & us_ufd) + sprintf (rname, "%03d%03d.dir", f->cproj, f->cprog); + else { + readlk (f->nlink); + r50filename (use(ufdne,k)->unam, + rname, FALSE); + } + if (sw.tree != NULL) { + if (cproj != f->cproj || cprog != f->cprog) { + cproj = f->cproj; + cprog = f->cprog; + sprintf (dirname, "%s/%03d%03d", on, cproj, cprog); + if (stat (dirname, &sbuf2)) { + if (errno != ENOENT) { + printf ("Can't stat %s\n", dirname); + perror (progname); + return; + } +#ifdef __unix__ + if (mkdir (dirname, mkdirmode)) { +#else + if (mkdir (dirname)) { +#endif + printf ("Can't mkdir %s\n", dirname); + perror (progname); + return; + } + } + } + sprintf (tmpname, "%s/%s", dirname, rname); + } else sprintf (tmpname, "%s/%s", on, rname); + on2 = tmpname; + } else on2 = on; + +/* open mode rule for copying to individual files: + * if -b is specified, use binary mode + * if -a is specified, use ascii mode + * else (no mode switch), the choice depends on the + * RMS file attributes, if any, of the input file: + * non-RMS files: + * if extension indicates text file, use ascii mode + * else use binary mode + * directory: use binary mode + * RMS sequential files: + * if fixed length records, recordsize a multiple of 512, use binary mode + * else use ascii mode + * Other RMS organizations, use binary mode + */ + + if (sw.bswitch != NULL) binmode = TRUE; + else if (sw.ascii != NULL) binmode = FALSE; + else { + if (f->stat & us_ufd) binmode = TRUE; + else if (NULLINK(f->rmslink)) + binmode = !textfile (f->cname); + else { + if ((f->recfmt & fa_org) == fo_seq) { + if ((f->recfmt & fa_rfm) == rf_fix + && (f->recsiz & 511) == 0) + binmode = TRUE; + else binmode = FALSE; + } else binmode = TRUE; + } + } + if (binmode) openmode = "wb"; + else openmode = "w"; + if (sw.debug != NULL) + printf ("get mode %s\n", openmode); + of = fopen (on2, openmode); + if (of == NULL) { + printf ("can't create %s\n", on2); + perror (progname); + return; + } + } + matches++; /* found another */ + tmatches++; + filebytes = getfile (of, f, binmode); + tbytes += filebytes; + if (!concat) fclose (of); + if (sw.verbose != NULL) { + printcurname (f); + if (concat && tmatches > 1) + printf (" =>> %s (%ld bytes) in ", on, filebytes); + else printf (" => %s (%ld bytes) in ", on2, filebytes); + if (binmode) printf ("block mode\n"); + else printf ("line mode\n"); + } +} + +void doget (int argc, char **argv) +{ + int s; + firqb f; + + if (argc < 2) { + printf ("Usage: %s get file... dest\n", progname); + return; + } + on = argv[--argc]; /* for convenience */ + cproj = cprog = 0; /* no current PPN yet */ + tmatches = 0; /* total matches */ + tbytes = 0; /* and total bytes */ + if (stat (on, &sbuf)) { /* stat the output spec */ + if (errno != ENOENT) { + printf ("can't stat %s\n", on); + perror (progname); /* report any details */ + return; /* and give up right now */ + } else sbuf.st_mode = 0; /* not found -> not a dir */ + } + s = strlen (on); + if (on[s - 1] == '/') on[s - 1] = '\0'; + on2 = on; + /* concatenating if output is a filespec (not a directory spec) + * and input spec is wildcard, or multiple input specs + */ + parse (argv[1], &f); /* parse first argument for wildcards */ + concat = (!S_ISDIR(sbuf.st_mode) && + (((f.flags & F_WILD) != 0) || argc >= 2)); + if (concat) { /* create now if concatenating */ + if (sw.bswitch == NULL) { + openmode = "w"; /* ascii mode */ + binmode = FALSE; + } else { + openmode = "wb"; /* binary mode */ + binmode = TRUE; + } + if ((of = fopen (on, openmode)) == NULL) { + printf ("can't create %s\n", on); + perror (progname); /* report any details */ + return; /* and give up right now */ + } + } + rmount (); /* mount the disk */ + dofiles (argc, argv, dogetfile, NULLISNULL); + if (concat) fclose (of); + if (sw.verbose != NULL && matches != 0) + printf ("Total files: %ld, total bytes: %ld\n", tmatches, tbytes); + rumount (); /* done with the disk */ +} + diff --git a/extracters/rstsflx/doget.h b/extracters/rstsflx/doget.h new file mode 100644 index 0000000..eaae1cc --- /dev/null +++ b/extracters/rstsflx/doget.h @@ -0,0 +1 @@ +extern void doget(int argc , char ** argv); diff --git a/extracters/rstsflx/dohook.c b/extracters/rstsflx/dohook.c new file mode 100644 index 0000000..2a248fe --- /dev/null +++ b/extracters/rstsflx/dohook.c @@ -0,0 +1,350 @@ +/* handler for the "hook" command */ + +#include +#include +#include +#include + +#include "flx.h" +#include "fldef.h" +#include "silfmt.h" +#include "dohook.h" +#include "fip.h" +#include "filename.h" +#include "fileio.h" +#include "diskio.h" + +typedef struct { /* boot data pointer in boot block */ + word16 lbn[2]; /* block number, LSW first */ + word16 wcnt; /* word count */ +} bdesc; + +typedef struct { /* header of boot block */ + word16 nop; /* nop required for boot */ + word16 setup_br; /* go do setup and relocation code */ + word16 trap4_vec[2]; /* if trap to 4, halt @ 6 w/ 10 in lights */ + word16 trap10_vec[2]; /* if trap to 10, halt @ 12 w/ 14 in lights */ + word16 clustr; /* 14 cluster size */ + word16 csr; /* 16 csr base */ + word16 devnam; /* 20 device name */ + word16 jmp; /* 22 jump to start address */ + word16 transfer; /* 24 transfer address (set by hook) */ + byte unit; /* 26 unit # in bits <2:0> (set by boot) */ + byte flags; /* 27 flags (definitions are in inidfn) */ + word16 unit_csr; /* 30 unit # in bits for csr (set by boot) */ + byte rc, wc; /* 32 read and write codes */ + word16 function; /* 34 function code: read */ + word16 blknum[2]; /* 36-40 block number to read, also spec func. */ + word16 memadr[2]; /* 42-44 memory address to read into */ + word16 wcnt; /* 46 word count, also spec function parameter */ + word16 reset; /* 50 do a device reset */ + word16 read; /* 52 do a single transfer */ + word16 spec; /* 54 do a magtape special function */ +} bhdr; + +int stbcnt, ovrcnt; /* SIL STB and OVR table entry count */ +stbent *stb = NULL; /* pointer to STB buffer */ +ovrent *ovr = NULL; /* pointer to OVR buffer */ + +/* note 0 rather than NULL because NULL is generally defined wrong + * (causing a warning that is a nuisance though it does no harm) + */ +const char disks[][3] = { "dv","df","ds","dk","dl","dm", + "dp","db","dr","dz","dw","du", + 0 }; + +long findsym (const char *sym) +{ + word16 r50[2]; + int n; + stbent *s; + ovrent *o; + + cvtnametor50 (sym, r50); /* convert symbol to rad50 */ + s = stb; /* point to start of stb */ + for (n = 0; n < stbcnt; n++, s++) + { + if (s->name[0] == r50[0] && s->name[1] == r50[1]) + { + if (s->ovnum >= ovrcnt) + { + printf ("Bad STB entry for %s\n", sym); + return (-1); + } + if (s->ovnum == 0) return (s->value); + o = &ovr[s->ovnum]; + return (s->value - o->base + + (o->offset[0] << 16) + o->offset[1]); + } + } + return (-1); +} + +void setptr (long blk, long size, void *buf) +{ + bdesc *b; + + b = (bdesc *) buf; /* point to where descriptor goes */ + b->wcnt = size / 2; /* set word count */ + b->lbn[0] = blk & 0xffff; /* low order LBN */ + b->lbn[1] = blk >> 16; /* and high order */ +} + +#define SIL 074064 /* rad50 "SIL" */ + +int silchk (firqb *f, savsilindex *x) +{ + word16 cs; + word16 *p; + + p = &(x->si_sil); + if (*p != SIL) /* verify SIL marker */ + { + printcurname (f); + printf (" is not a SIL\n"); + return (FALSE); + } + cs = 0; /* initialize checksum */ + do cs ^= *--p; /* XOR checksum of the rest */ + while (p != (word16 *)x); + if (cs != 0) + { + printf ("checksum error in SIL "); + printcurname (f); + printf ("\n"); + return (FALSE); + } + return (TRUE); /* it's ok */ +} + +/* read file data for some given byte address, and return a pointer to + * where it is. There's at least 512 valid bytes after that point. + */ + +/* this routine reads data from the file, doing the full count requested + * even if it requires multiple calls to seqio. (note that seqio only + * reads a single contiguous piece of file.) + */ + +void readfile (firqb *f, long count, void *buf) +{ + long rcnt; + byte *b; /* workaround cc bug */ + + b = (byte *) buf; + while (count) + { + rcnt = seqio (f, count, rread, b); + if (rcnt == 0) return; /* eof??? */ + b += rcnt; /* adjust by what we read */ + count -= rcnt; /* and count also */ + } +} + +void *getdata (firqb *f, long address) +{ + fileseek (f, address / BLKSIZE); /* seek to the right start block */ + readfile (f, BLKSIZE * 2, iobuf); + return (iobuf + (address % BLKSIZE)); +} + +void cleanup () +{ + rumountrw (); + if (ovr != NULL) free (ovr); + ovr = NULL; + if (stb != NULL) free (stb); + stb = NULL; + return; +} + +void dohook (int argc, char **argv) +{ + savsilindex idx; /* SIL index buffer */ + int n; + firqb hf; /* file to be hooked */ + firqb bf; /* file where bootstraps are */ + char *disk; /* bootstrap name */ + byte bbuf[BLKSIZE]; /* boot block buffer */ + bdesc *bd; /* pointer to current boot data desc */ + bhdr *bh; /* pointer to boot header */ + int dskio, dskioe, xxboot; /* symbols from SIL */ + int dskidx; /* disk index for boot disk name */ + void *btop; /* pointer to end of boot code */ + short int xxent; /* xxboot table entry */ + int pcoffset; /* offset to apply to entry point */ + char *p; + + if (argc == 0) disk = "dl"; + else + { + disk = argv[0]; /* disk is first argument */ + if (strlen (disk) != 2 ) { + printf ("Invalid disk name %s\n", disk); + return; + } + disk[0] = tolower (disk[0]); + if (disk[0] == 'r') disk[0] = 'd'; + disk[1] = tolower (disk[1]); + } + for (dskidx = 0; ; dskidx++) + { + if (disks[dskidx] == NULL) + { + printf ("Unknown disk name %s\n", disk); + return; + } + if (strcmp (disks[dskidx], disk) == 0) break; + } + if (sw.odt != NULL) pcoffset = 2; + else if (sw.offset == NULL) pcoffset = 0; + else + { + pcoffset = strtol (sw.offset, &p, 10); + if (*p != '\0' || (pcoffset & 1) != 0) + { + printf ("Invalid offset %s\n", sw.offset); + return; + } + } + dskidx *= 2; /* make even (byte offset) */ + rmountrw (); /* mount disk for read/write */ + if (argc < 2) parse ("[0,1]init.sys", &hf); + else + { + if (!parse (argv[1], &hf) || hf.flags & F_WILD) + { + cleanup (); + printf ("Invalid filespec %s\n", argv[1]); + return; + } + if ((hf.flags & f_ppn) == 0) + { + hf.proj = 0; + hf.prog = 1; + } + } + if (argc < 3) memcpy (&bf, &hf, sizeof (firqb)); + else { + if (!parse (argv[2], &bf) || bf.flags & F_WILD) + { + cleanup (); + printf ("Invalid filespec %s\n", argv[2]); + return; + } + if ((bf.flags & f_ppn) == 0) + { + bf.proj = 0; + bf.prog = 1; + } + } + if (initfilescan (&bf, gfddcntbl) == 0 || + nextfile (&bf) == 0) + { + printfqbname (&bf); + printf (" not found\n"); + cleanup (); + return; + } + initrandom (&bf); /* set up random access to bootfile */ + seqio (&bf, sizeof(idx), rread, &idx); /* read sil index */ + if (!silchk (&bf, &idx)) + { + cleanup (); + return; /* quit if bad sil index */ + } + stbcnt = idx.si_ent.se_stn; /* copy STB and OVR sizes */ + ovrcnt = idx.si_ent.se_ovn; + if ((stb = (stbent *) malloc (UP(stbcnt * sizeof (stbent),BLKSIZE))) == NULL) + { + cleanup (); + rabort(NOMEM); + } + if ((ovr = (ovrent *) malloc (UP(ovrcnt * sizeof (ovrent),BLKSIZE))) == NULL) + { + cleanup (); + rabort(NOMEM); + } + fileseek (&bf, idx.si_ent.se_stb); /* read symbol table */ + readfile (&bf, UP(stbcnt * sizeof (stbent),BLKSIZE), stb); + fileseek (&bf, idx.si_ent.se_ovb); /* read symbol table */ + readfile (&bf, UP(ovrcnt * sizeof (ovrent),BLKSIZE), ovr); + memset (bbuf, 0, BLKSIZE); /* zero out boot buffer */ + if ((xxboot = findsym ("xxboot")) < 0) + { + cleanup (); + printf ("Symbol XXBOOT not found\n"); + return; + } + if ((dskioe = findsym ("dskioe")) < 0) + { + cleanup (); + printf ("Symbol DSKIOE not found\n"); + return; + } + if ((dskio = findsym ("dskio")) < 0) dskio = dskioe - 72; + xxboot += dskidx; /* point to entry for selected disk */ + xxent = *(short int *)(getdata (&bf, xxboot)); + if (xxent == 0) + { + cleanup (); + printf ("No bootstrap for %s\n", disk); + return; + } + xxboot += xxent; /* point to bootstrap */ + bh = (bhdr *)(getdata (&bf, xxboot)); /* read it */ + n = bh->wcnt; /* get bootstrap size in bytes */ + memcpy (bbuf, bh, n); /* copy that into boot buffer */ + memcpy (bbuf + n, getdata (&bf, dskio), dskioe - dskio); + /* append boot mainline */ + btop = bbuf + n + (dskioe - dskio); + if (initfilescan (&hf, gfddcntbl) == 0 || + nextfile (&hf) == 0) + { + printcurname (&hf); + printf (" not found\n"); + } + openfile (&hf); /* set up to read file to hook */ + seqio (&bf, sizeof(idx), rread, &idx); /* read sil index */ + if (!silchk (&hf, &idx)) + { + cleanup (); + return; /* quit if bad sil index */ + } + openfile (&hf); /* reset to start over at VBN 0 */ + if (idx.usertop >= 0157000) + { + cleanup (); + printcurname (&hf); + printf (" high limit is too high (%06o)\n", idx.usertop); + return; + } + + n = UP(idx.usertop + 2,BLKSIZE); /* compute byte count to boot */ + ((bhdr *) bbuf)->transfer = idx.initpc + pcoffset; + /* set transfer address in bootstrap */ + ((bhdr *) bbuf)->clustr = dcs; /* set clustersize */ + bd = (bdesc *)(&bbuf[0772]); /* initialize boot desc pointer */ + while (n) + { + if (--bd < (bdesc *)btop) /* check for bootstrap full */ + { + cleanup (); + printcurname (&hf); + printf (" is too fragmented to hook\n"); + return; + } + n -= seqio (&hf, n, setptr, bd); + } + rwrite (0, BLKSIZE, bbuf); /* write boot block */ + if (sw.verbose != NULL) + { + printcurname (&hf); + if (sw.offset == NULL && sw.odt == NULL) + printf (" hooked, start PC = %06o\n", idx.initpc); + else printf (" hooked, start PC = %06o, offset %d\n", + idx.initpc + pcoffset, pcoffset); + } + cleanup (); /* clean up now */ + return; /* and we're done */ +} diff --git a/extracters/rstsflx/dohook.h b/extracters/rstsflx/dohook.h new file mode 100644 index 0000000..4e4faf5 --- /dev/null +++ b/extracters/rstsflx/dohook.h @@ -0,0 +1,13 @@ +extern long findsym(const char * sym); +extern void setptr(long blk , long size , void * buf); +extern int silchk(firqb * f , savsilindex * x); + /* Prototype include a typedef name. + It should be moved after the typedef declaration */ +extern void readfile(firqb * f , long count , void * buf); + /* Prototype include a typedef name. + It should be moved after the typedef declaration */ +extern void * getdata(firqb * f , long address); + /* Prototype include a typedef name. + It should be moved after the typedef declaration */ +extern void cleanup(void); +extern void dohook(int argc , char ** argv); diff --git a/extracters/rstsflx/doident.c b/extracters/rstsflx/doident.c new file mode 100644 index 0000000..2038425 --- /dev/null +++ b/extracters/rstsflx/doident.c @@ -0,0 +1,48 @@ +/* handler for the "identify" command */ + +#include + +#include "flx.h" +#include "fldef.h" +#include "doident.h" +#include "fip.h" +#include "rtime.h" + +void doident (int argc, char **argv) /* show pack id data */ +{ + packlabel *p; + char rdate[DATELEN]; + char rtime[RTIMELEN]; + + rmount (); /* mount the disk R/O */ + readdcn (1); /* get the pack label */ + p = use(packlabel,0); + if (p->fill1 == -1 + && (pcs >= dcs) + && ((pcs & (-pcs)) == pcs)) { + printf ("RSTS disk on %s -- \"%s\"\n", rname, pname); + printf (" Device clustersize: %d\n", dcs); + printf (" Pack clustersize: %d\n", pcs); + if (dcs > 1) + printf (" Device size: %ld (%ld DCNs)\n", + diskblocks, diskblocks / dcs); + else printf (" Device size: %ld\n", diskblocks); + printf (" Revision level: %d.%d\n", plevel >> 8, plevel & 0377); + if (plevel >= RDS12) { + cvtdate (p->mntdat, rdate); + cvttime (p->mnttim, rtime); + printf (" Last mount date: %s\n", rdate); + printf (" Last mount time: %s\n", rtime); + } + printf (" Pack flags: "); + if (p->pstat & uc_mnt) printf (" Dirty"); + if (p->pstat & uc_pri) printf (" Private/system"); + else printf (" Public"); + if (p->pstat & uc_ro) printf (" Read-only"); + if (p->pstat & uc_dlw) printf (" DLW"); + if (p->pstat & uc_top) printf (" NFF"); + printf ("\n"); + } else printf ("Disk on %s does not appear to be a RSTS format disk\n", rname); + rumount (); /* done with disk */ +} + diff --git a/extracters/rstsflx/doident.h b/extracters/rstsflx/doident.h new file mode 100644 index 0000000..3e52722 --- /dev/null +++ b/extracters/rstsflx/doident.h @@ -0,0 +1 @@ +extern void doident(int argc , char ** argv); diff --git a/extracters/rstsflx/doinit.c b/extracters/rstsflx/doinit.c new file mode 100644 index 0000000..e006b40 --- /dev/null +++ b/extracters/rstsflx/doinit.c @@ -0,0 +1,387 @@ +/* handler for the "initialize" command */ + +#include +#include +#include +#include +#include +#include +#include + +#include "flx.h" +#include "fldef.h" +#include "doinit.h" +#include "fip.h" +#include "diskio.h" +#include "filename.h" + +#define MFDCLU 16 +#define UFDCLU 16 +#define DEC166COUNT 10 /* number of bad block tables */ + +int getclusize () +{ + int newclu; + char *p; + + if (sw.clusiz == NULL) return (dcs); + else { + newclu = strtol (sw.clusiz, &p, 10); + if (newclu < 0) { + newclu = -newclu; + if (newclu < dcs) newclu = dcs; + } + if (*p != '\0' || newclu < dcs || newclu > 64 || + (newclu & (-newclu)) != newclu) { + printf ("Invalid clustersize %s\n", sw.clusiz); + return (0); + } + } + return (newclu); +} + +#define PSTAT (uc_dlw | uc_pri) /* pack flags to use */ +#define MRECNT 20 /* max RE's for merge.sys */ + +const ufdlabel newmlabel = { 0, 0177777, {0, 0, 0, 0}, {255, 255}, MFD}; +const word16 rstsrts[2] = { 001343, 077770 }; /* rad50 " RSTS " */ + +/* Dummy bootstrap */ + +const word16 dummyboot[] = { + 0000240, /* NOP ; */ + 0000005, /* RESET ;UGH */ + 0000402, /* BR 5$ ;Go to the real code */ + + 0000020,0153430,0000400,/* BOOTID 5$,<> ;Boot ID block, no controllers */ + + 0005067,0000002, /* 5$: CLR 20$ ;COUNT DOWN MEMORY TO DELAY */ + 0005327, /* 10$: DEC (PC)+ ;CHURN */ + 0000000, /* 20$: .WORD 0 ; */ + 0001375, /* BNE 10$ ; */ + 0010700, /* MOV PC,R0 ;GETTA POSITION INDEPENDENT MESSAGE */ + 0062700,0000026, /* ADD #40$-.,R0 ;ADDRESS INTO R0 */ + 0105737,0177564, /* 30$: TSTB @#177564 ;CONSOLE READY ? */ + 0100375, /* BPL 30$ ;PATIENCE */ + 0112037,0177566, /* MOVB (R0)+,@#177566 ;TALK TO ME */ + 0105710, /* TSTB (R0) ;ANY MORE ? */ + 0001371, /* BNE 30$ ;YUP */ + 0000000, /* HALT ;NOPE */ + 0000751 /* BR DUMBOT ;DO IT AGAIN IF HE CONTINUES */ + + /* 40$: ;String starts here */ + }; + +#define dummytext "\a\a\r\nPlease boot from the system disk\r\n" + +void doinit (int argc, char **argv) +{ + long n, count, sattblks; + firqb f, packid; + long newclu, newsize, newrsize; + int dec166; + long newlevel, mfdclu, ufdlbn; + char *p; + char answer[20]; + struct stat sbuf; + word dirne; + packlabel *l; + ufdae *a; + FILE *mf; + long mblocks, moblk, mbytes, mreoff; + word mprevre, mre; + + if (argc == 0) { + printf ("Usage: %s initialize packid [level]\n", progname); + return; + } + packid.flags = 0; + if (*parsename (argv[0], &packid) != '\0' || (packid.flags & F_WILD)) { + printf ("Invalid pack id %s\n", argv[0]); + return; + } + if (argc < 2) newlevel = RDS12; + else { + p = argv[1]; + if (tolower (*p) == 'r') { + p++; + if (tolower (*p++) != 'd' || tolower (*p++) != 's') { + printf ("Invalid revision level %s\n", argv[1]); + return; + } + } + while (*p == ' ') p++; + if (strcmp (p, "0") == 0) newlevel = RDS0; + else if (strcmp (p, "0.0") == 0) newlevel = RDS0; + else if (strcmp (p, "1.1") == 0) newlevel = RDS11; + else if (strcmp (p, "1.2") == 0) newlevel = RDS12; + else { + printf ("Invalid revision level %s\n", argv[1]); + return; + } + } + if (sw.merge != NULL) { /* merging another filesystem */ + if (newlevel == RDS0) { + printf ("-merge not allowed for RDS 0.0\n"); + return; + } + if ((mf = fopen (sw.merge, "rb")) == NULL) { + printf ("Can't open merge file %s\n", sw.merge); + perror (progname); + return; + } + if (fstat (fileno(mf), &sbuf)) { /* get info about input file */ + printf ("Can't stat merge file %s", sw.merge); + perror (progname); + fclose (mf); /* close input */ + return; + } + mblocks = UP(sbuf.st_size,BLKSIZE) / BLKSIZE; + } + if (sw.create != NULL) { + getsize (sw.create, &newsize, &newrsize, &dec166); + if (newsize == 0 || + newsize < 800 || + newsize >= (1 << 23)) { + printf ("Invalid container size %s\n", sw.create); + return; + } + diskblocks = newsize; /* allow writing it all */ + n = (newrsize - 1) >> 16; /* high order bits of last LBN */ + dcs = 1; /* compute DCS */ + while (n) { + n >>= 1; + dcs <<= 1; + } + if (dcs > 16 && newlevel != RDS12) + { + printf ("Large disk requires RDS 1.2\n"); + return; + } + newclu = getclusize (); + setrname (); /* set container name */ + if (stat (rname, &sbuf)) { + if (errno != ENOENT) { + printf ("Can't stat %s\n", rname); + return; + } + } else { + printf ("Container file %s already exists\n", rname); + return; + } + if ((rstsfile = fopen (rname, DCREATEMODE)) == NULL) { + printf ("Error opening container file %s\n", rname); + perror (progname); /* report any details */ + return; + } + memset (iobuf, 0, iobufsize); /* zero the entire buffer */ + for (n = 0; n < newsize; n += iobufsize / BLKSIZE) { + count = iobufsize / BLKSIZE; + if (newsize - n < count) count = newsize - n; + rwrite (n, count * BLKSIZE, iobuf); + } + if (dec166) { /* set up bad block table */ + word16 *w; + memset (iobuf, -1, BLKSIZE); /* set end marker */ + w = (word16 *)iobuf; + *w++ = 031416; /* random serial number */ + *w++ = 0; /* and high order */ + *w++ = 0; /* reserved word */ + *w = 0; /* mark as data pack */ + for (n = 0; n < DEC166COUNT; n++) + rwrite (newrsize + n, BLKSIZE, iobuf); + } + diskblocks = newrsize; + } else { + ropen (DWRITEMODE); + if (dcs > 16 && newlevel != RDS12) + { + printf ("Large disk requires RDS 1.2\n"); + return; + } + newclu = getclusize (); + readlabel (); + if (use(packlabel,0)->fill1 == -1 + && (pcs >= dcs) + && ((pcs & (-pcs)) == pcs)) { + printf ("Disk %s appears to be a RSTS format disk:\n", rname); + printf (" Clustersize: %d\n", pcs); + printf (" Revision: %d.%d\n", plevel >> 8, plevel & 0xff); + printf (" Pack label: %s\n", pname); + printf ("\nRe-initialize it (Y/N)? "); + } else printf ("Initialize %s (Y/N)? ", rname); + fgets (answer, sizeof (answer), stdin); + if (tolower(answer[0]) != 'y') return; + } + fiblk = dcntolbn(1); + memset (fibuf, 0, BLKSIZE); /* clear out fibuf to make an invalid pack */ + fbwrite (); /* write that out */ + pcs = newclu; /* set new PCS */ + f.clusiz = pcs; /* clustersize for files */ + plevel = newlevel; /* set up pack level being created */ + if (plevel == RDS0) pflags = PSTAT; + else pflags = PSTAT | uc_new; /* and flags also */ + pcns = (diskblocks - dcs) / pcs; /* compute PCN count */ + sattblks = UP(pcns,BLKSIZE*8) / (BLKSIZE * 8); /* SATT size in blocks */ + sattsize = sattblks * BLKSIZE; /* and in bytes */ + sattlbn = 1 << 23; /* set a fake SATT LBN */ + if ((sattbufp = (byte *) malloc (sattsize)) == NULL) rabort(NOMEM); + memset (sattbufp, 0xff, sattsize); /* first mark everything in use */ + memset (sattbufp, 0, pcns / 8); /* make all real clusters free */ + if (pcns & 7) sattbufp[pcns / 8] = 0xff << (pcns & 7); /* ditto any leftover bits */ + satptr = 0; /* MFD/label goes at the start */ + if (plevel == RDS0) { /* doing an old pack */ + if (!extdir2 (0, MFDCLU, 0, &newmlabel)) rabort(INTERNAL); + mfddcn = clumap->uent[0]; /* remember MFD start */ + if (sw.debug != NULL) printf ("mfd at %lo\n", mfddcn); + if (mfddcn != 1) rabort(INTERNAL); + curgfd = mfdlbn = dcntolbn(mfddcn); + f.cproj = f.cprog = 1; /* prepare to create [1,1] */ + prevppnlink = nextppnlink = 0; /* nothing in the MFD yet */ + if (!makedir (&f, MFDCLU)) rabort(INTERNAL); /* create MFD */ + readlk2 (0); /* re-read MFD label */ + dirne = use(packlabel,0)->ulnk; /* get [1,1] NE link */ + readlk (dirne); /* read that */ + use(gfdne,k)->uar = 1; /* fill in cluster pointer */ + MARKF; + satptr = pcns / 2; /* put the rest in the middle */ + } else { /* new (RDS1.1 or later) pack */ + if (sw.merge != 0) { /* do the merge */ + if (mblocks <= dcs) { /* merge fits in pack label */ + *sattbufp = 0x01; /* mark first cluster (pack label) allocated */ + } else { + if (getclu (pcs, UP(mblocks-dcs,pcs)) != 1) { + printf ("No room for merge data\n"); + rabort(INTERNAL); + } + } + moblk = 0; + while ((mbytes = fread (iobuf, 1, iobufsize, mf)) != 0) { + mbytes = UP(mbytes, BLKSIZE); + rwrite (moblk, mbytes, iobuf); + moblk += mbytes / BLKSIZE; + } + if (sw.verbose != NULL) + printf ("merged %s (%ld blocks)\n", + sw.merge, mblocks); + } else *sattbufp = 0x01; /* mark first cluster (pack label) allocated */ + satptr = pcns / 2; /* put the rest in the middle */ + mfdclu = MFDCLU; /* default MFD clustersize */ + if (pcs > mfdclu) mfdclu = pcs; + if (mfdclu > 16) mfdclu = 16; /* adjust it as needed */ + if (!extdir2 (0, mfdclu, fd_new, &newmlabel)) rabort(INTERNAL); + mfddcn = clumap->uent[0]; /* remember MFD start */ + if (sw.debug != NULL) printf ("mfd at %lo\n", mfddcn); + mfdlbn = dcntolbn(mfddcn); /* and LBN also */ + curgfd = 0; /* no [0,*] GFD yet */ + } + parse ("[0,1]badb.sys<63>", &f); /* set up firqb */ + f.cproj = f.proj; + f.cprog = f.prog; /* current also */ + memcpy (f.cname, f.name, NAMELEN); + if (!makedir (&f, UFDCLU)) rabort(INTERNAL); /* create [0,1] account */ + dirne = initfilescan (&f, gfdatrtbl); /* look up [0,1] NE pointer */ + if (sw.debug != NULL) printf ("[0,1] NE %o\n", dirne); + if ((ufdlbn = allocufd (dirne, &f)) == 0) rabort(INTERNAL); + /* allocate the UFD */ + fbread (ufdlbn); /* get it into fibuf */ + nextlink = prevlink = 0; + entptr = sizeof (ufdlabel); /* initialize pointers for crefile */ + f.stat = us_nok; /* we want P set for badb.sys */ + f.clusiz = pcs; /* default clustersize */ + if (!crefile (&f, rstsrts, NULL, NULL)) rabort(INTERNAL); + parse ("[0,1]satt.sys<63>", &f); /* set up firqb for the second file */ + f.cproj = f.proj; + f.cprog = f.prog; /* current also */ + memcpy (f.cname, f.name, NAMELEN); + f.stat = us_nok | us_nox; /* P set and contiguous */ + f.size = sattblks; /* we need this size */ + f.clusiz = pcs; /* default clustersize */ + if (!crefile (&f, rstsrts, NULL, NULL)) rabort(INTERNAL); + readlk (f.rlink); /* read first RE */ + sattlbn = dcntolbn(use(ufdre,k)->uent[0]); + if (sw.merge != NULL && (mblocks -= dcs + pcs) > 0) { + moblk = 1 + pcs / dcs; /* first DCN for merge.sys */ + parse ("[0,1]merge.sys<63>", &f); + f.cproj = f.proj; + f.cprog = f.prog; /* current also */ + memcpy (f.cname, f.name, NAMELEN); + f.stat = us_nok | us_nox; /* P set and contiguous */ + f.size = 0; /* don't allocate it now */ + f.clusiz = pcs; /* clustersize is PCS */ + if (!crefile (&f, rstsrts, NULL, NULL)) rabort(INTERNAL); + readlk (f.alink); + a = use(ufdae,k); + a->usiz = mblocks; + if (mblocks >> 16) { /* large file ! */ + a->urts[0] = 0; + a->urts[1] = mblocks >> 16; + } + MARKF; + mprevre = 0; + mreoff = 0; /* fill RE from top */ + while (mblocks > 0) { + if (mreoff == 0) { /* need a new RE */ + if ((mre = getent ()) == 0) { + printf ("No room in [0,1] for merge.sys\n"); + rabort(INTERNAL); + } + if (mprevre) { + readlk (mprevre); + use(ufdre,k)->ulnk = mre; + } else { + readlk (f.nlink); + use(ufdne,k)->uar = mre; + } + MARKF; + mprevre = mre; /* link to this next time */ + } + readlk (mre); + use(ufdre,k)->uent[mreoff] = moblk; + moblk += pcs / dcs; /* advance to next cluster */ + mblocks -= pcs; /* count down size to fill */ + mreoff++; + if (mreoff > 6) mreoff = 0; + } + } + rwrite (sattlbn, sattsize, sattbufp); /* now write the SATT data */ + womsat = FALSE; + free (sattbufp); /* deallocate SATT */ + checkwrite (); /* write FIBUF if needed */ + if (sw.merge != NULL) { /* see if overwriting merge data */ + fbread (0); /* read the boot block */ + for (n = 0; n < BLKSIZE; n++) { + if (fibuf[n] != 0) { + printf ("Warning: non-zero merge file data in boot block\n"); + break; + } + } + } + fiblk = 0; /* build the dummy boot */ + memset (fibuf, 0, BLKSIZE); /* clear it out */ + memcpy (fibuf, dummyboot, sizeof (dummyboot)); + memcpy (fibuf + sizeof (dummyboot), dummytext, sizeof (dummytext)); + fbwrite (); /* and write it */ + readdcn (1); /* re-read pack label */ + if (sw.merge != NULL) { /* see if overwriting merge data */ + for (n = 0; n < BLKSIZE; n++) { + if (fibuf[n] != 0) { + printf ("Warning: non-zero merge file data in pack label\n"); + break; + } + } + } + l = use(packlabel,0); + l->fill1 = 0177777; + l->ppcs = pcs; /* pack cluster size */ + if (plevel > RDS0) { /* if new pack, set new fields: */ + l->mdcn = mfddcn; /* MFD DCN */ + l->plvl = newlevel; /* and rev level */ + l->ulnk = 1; /* link field = 1 by convention */ + l->mntdat = l->mnttim = 0; /* never mounted yet */ + } + l->pstat = pflags; /* set pack flags */ + cvtnametor50 (packid.name, l->pckid); /* set the pack label */ + fbwrite (); /* write the pack label */ + rclose (); /* and that's all! */ +} diff --git a/extracters/rstsflx/doinit.h b/extracters/rstsflx/doinit.h new file mode 100644 index 0000000..5da173d --- /dev/null +++ b/extracters/rstsflx/doinit.h @@ -0,0 +1,2 @@ +extern int getclusize(void); +extern void doinit(int argc , char * argv[]); diff --git a/extracters/rstsflx/dolist.c b/extracters/rstsflx/dolist.c new file mode 100644 index 0000000..41a5361 --- /dev/null +++ b/extracters/rstsflx/dolist.c @@ -0,0 +1,218 @@ +/* handler for the "list" command */ + +#include +#include + +#include "flx.h" +#include "fldef.h" +#include "dolist.h" +#include "fip.h" +#include "rtime.h" +#include "filename.h" +#include "scancmd.h" + +#define COLUMNS 5 + +long files, blocks, tfiles, tblocks; +byte curproj, curprog; + +static void dolistfqb (firqb *f) +{ + word utc; + ufdae *a; + ufdrms1 *r1; + ufdrms2 *r2; + int pos; + int line2; + char rts[RTSLEN]; + char stat[4]; + char credate[DATELEN], acdate[DATELEN], cretime[RTIMELEN]; + char *sp; + + if (sw.narrow != NULL) sw.bswitch = sw.narrow; /* -1 implies -b */ + if (f->cproj != curproj || f->cprog != curprog) + { + if (curproj != 0 || curprog != 0) + { + if (sw.bswitch != NULL) + { + if (sw.narrow != NULL + || files % COLUMNS == 0) + printf ("\n"); + else printf ("\n\n"); + } + else + { + printf (" Total of %ld blocks in %ld files in [%d,%d]\n", + blocks, files, curproj, curprog); + } + } + files = 0; + blocks = 0; + curproj = f->cproj; + curprog = f->cprog; + if (sw.summary == NULL) + { + if (sw.bswitch != NULL) + { + if (sw.narrow == NULL) + printf ("[%d,%d]\n", curproj, curprog); + } + else + { + printf ("\nDirectory of [%d,%d]\n" + " Name .Ext Size Prot Access" + " Creation Clu" + " RTS Pos\n", + curproj, curprog); + } + } + } + files++; /* accumulate totals */ + tfiles++; + blocks += f->size; + tblocks += f->size; + if (sw.summary != NULL) return; + if (sw.bswitch != NULL) { /* brief listing */ + if (sw.narrow != NULL || files % COLUMNS == 0) + printf ("%-10s\n", f->cname); + else printf ("%-10s ", f->cname); + return; + } + sp = stat; /* point to status buffer */ + if (f->stat & us_nox) *sp++ = 'C'; + if (f->stat & us_nok) *sp++ = 'P'; + if (f->stat & us_plc) *sp++ = 'L'; + *sp = '\0'; /* put in terminator */ + readlk (f->alink); /* make sure we have the AE */ + a = use(ufdae,k); /* and point to it */ + cvtdate (a->udla, acdate); /* convert dates and time */ + cvtdate (a->udc, credate); + utc = a->utc; /* save time (for flags) */ + cvttime (utc, cretime); + if (a->urts[0] != 0) + r50toascii2 (a->urts, rts, TRUE); + else memcpy (rts, " ", RTSLEN); + if (f->size == 0) + printf ("%-10s%8ld%-3s <%3d> %11s %11s %8s %3d %-6s ----\n", + f->cname, f->size, stat, f->prot, + acdate, credate, cretime, f->clusiz, rts); + else + { + if (!readlk (f->rlink)) rabort (CORRUPT); + pos = use(ufdre,k)->uent[0]; /* Get first retrieval entry */ + printf ("%-10s%8ld%-3s <%3d> %9s %9s %8s %3d %-6s %6d\n", + f->cname, f->size, stat, f->prot, + acdate, credate, cretime, f->clusiz, rts, pos); + } + if (sw.full != NULL) { /* full listing */ + line2 = FALSE; /* no flags line yet */ + if (f->nlink & ul_che) + { + line2 = TRUE; + printf (" cache:on"); + if (f->alink & ul_che) printf (":seq"); + else printf (":ran"); + } + if (utc & (utc_ig | utc_bk)) + { + if (line2) printf (" "); + line2 = TRUE; + if (utc & utc_ig) printf (" ignore"); + if (utc & utc_bk) printf (" nobackup"); + } + if (line2) printf ("\n"); + if (readlk (f->rmslink)) { /* if RMS attributes present */ + r1 = use(ufdrms1,k); + printf (" rfm:"); + switch (r1->fa_typ & fa_rfm) + { + case rf_udf: printf ("ufd"); break; + case rf_fix: printf ("fix"); break; + case rf_var: printf ("var"); break; + case rf_vfc: printf ("vfc"); break; + case rf_stm: printf ("stm"); break; + } + switch (r1->fa_typ & fa_org) + { + case fo_seq: printf (":seq"); break; + case fo_rel: printf (":rel"); break; + case fo_idx: printf (":idx"); break; + } + if (r1->fa_typ & fa_rat) + { + printf (" rat"); + if (r1->fa_typ & ra_ftn) printf (":ftn"); + if (r1->fa_typ & ra_imp) printf (":imp"); + if (r1->fa_typ & ra_spn) printf (":nospan"); + } + printf (" rsz:%d size:%ld eof:%ld:%d", + r1->fa_rsz, + ((long)(r1->fa_siz[0]) << 16) + r1->fa_siz[1], + ((long)(r1->fa_eof[0]) << 16) + r1->fa_eof[1], + r1->fa_eofb); + if (readlk (r1->ulnk)) + { + r2 = use(ufdrms2,k); + printf (" bkt:%d hdr:%d msz:%d ext:%d", + r2->fa_bkt, r2->fa_hsz, + r2->fa_msz, r2->fa_ext); + } + printf ("\n"); + } + } + if (sw.oattr != NULL && readlk (f->rmslink)) + { + r1 = use(ufdrms1,k); + printf (" %06o %06o %06o %06o %06o %06o %06o", + r1->fa_typ, r1->fa_rsz, + r1->fa_siz[0], r1->fa_siz[1], + r1->fa_eof[0], r1->fa_eof[1], + r1->fa_eofb); + if (readlk(r1->ulnk)) + { + r2 = use(ufdrms2,k); + printf (" %03o %03o %06o %06o", + r2->fa_bkt, r2->fa_hsz, + r2->fa_msz, r2->fa_ext); + } + printf ("\n"); + } +} + +void dolist (int argc, char **argv) +{ + if (argc == 0) + { + argv[0] = "[*,*]"; + argc = 1; + } + tfiles = 0; + tblocks = 0; + curproj = 0; + curprog = 0; + rmount (); /* mount the disk */ + sw.query = NULL; /* force -query to be absent */ + dofiles (argc, argv, dolistfqb, NULLISWILD); + if (tfiles != 0) + { + if (sw.bswitch != NULL) + { + if (sw.narrow == NULL && files % COLUMNS != 0) + printf ("\n"); + } + else + { + if (sw.summary == NULL) + printf (" Total of %ld blocks in %ld files\n", + blocks, files); + else printf (" Total of %ld blocks in %ld files in [%d,%d]\n", + blocks, files, curproj, curprog); + if (tfiles != files) + printf (" Grand total of %ld blocks in %ld files\n", + tblocks, tfiles); + } + } + rumount (); /* done with disk */ +} + diff --git a/extracters/rstsflx/dolist.h b/extracters/rstsflx/dolist.h new file mode 100644 index 0000000..062c16c --- /dev/null +++ b/extracters/rstsflx/dolist.h @@ -0,0 +1 @@ +extern void dolist(int argc , char ** argv); diff --git a/extracters/rstsflx/doprot.c b/extracters/rstsflx/doprot.c new file mode 100644 index 0000000..09577d3 --- /dev/null +++ b/extracters/rstsflx/doprot.c @@ -0,0 +1,54 @@ +/* handler for the "prot" command */ + +#include + +#include "flx.h" +#include "fldef.h" +#include "doprot.h" +#include "fip.h" +#include "filename.h" +#include "fileio.h" +#include "scancmd.h" + +void doprot2 (firqb *f) +{ + ufdne *n; + + readlk (f->nlink); /* read the NE for this file */ + n = use(ufdne,k); + if (sw.prot != NULL) { + n->ustat |= us_nok; /* set no-kill bit */ + if (sw.verbose != NULL) { + printcurname (f); + printf (" marked no-delete\n"); + } + } else if (sw.unprot != NULL) { + n->ustat &= ~us_nok; /* clear no-kill bit */ + if (sw.verbose != NULL) { + printcurname (f); + printf (" no longer marked marked no-delete\n"); + } + } else { + if ((f->flags & f_prot) == 0) { + printf ("File "); + printcurname (f); + printf (" not changed, no protection specified\n"); + return; + } + n->uprot = f->newprot; + if (sw.verbose != NULL) { + printf ("File "); + printcurname (f); + printf (" protection changed to <%d>\n", f->newprot); + } + } + MARKF; + upddlw (f); +} + +void doprot (int argc, char **argv) +{ + rmountrw (); /* mount the disk */ + dofiles (argc, argv, doprot2, NOTNULL); + rumountrw (); /* done with disk */ +} diff --git a/extracters/rstsflx/doprot.h b/extracters/rstsflx/doprot.h new file mode 100644 index 0000000..218d7cc --- /dev/null +++ b/extracters/rstsflx/doprot.h @@ -0,0 +1,4 @@ +extern void doprot2(firqb * f); + /* Prototype include a typedef name. + It should be moved after the typedef declaration */ +extern void doprot(int argc , char ** argv); diff --git a/extracters/rstsflx/doput.c b/extracters/rstsflx/doput.c new file mode 100644 index 0000000..d048f1d --- /dev/null +++ b/extracters/rstsflx/doput.c @@ -0,0 +1,301 @@ +/* handler for "put" command */ + +#include +#include +#include +#include +#include + +#include "flx.h" +#include "fldef.h" +#include "doput.h" +#include "fip.h" +#include "filename.h" +#include "fileio.h" +#include "scancmd.h" + +typedef struct { + const char *ext; + const char *rts; +} rtsent; + +const rtsent rtstbl[] = { + { "tsk", "...rsx" }, + { "sav", "rt11 " }, + { "4th", "forth " }, + { "bas", "basic " }, + { "tec", "teco " }, + { "com", "dcl " }, + { "alc", "algol " }, + { "wps", "wpsedt" }, + { NULL, NULL }}; + +/* check for extension match against runtime system runnable extensions. + * Return TRUE and rts name if a match, false and zeroes otherwise. + */ + +static int checkrts (firqb *f, word16 *rtsname) +{ + const rtsent *r; + + for (r = rtstbl; r->ext != NULL; r++) { + if (strncmp (&(f->cname[7]), r->ext, 3) == 0) { + cvtnametor50 (r->rts, rtsname); + return (TRUE); + } + } + rtsname[0] = rtsname[1] = 0; + return (FALSE); +} + +static void putname (void *name) { + fputs ((char *) name, stdout); +} + +void doput (int argc, char **argv) +{ + char *p, *pp; + FILE *inf; + long newsize; + int newclu; + word16 rtsname[2]; + char *inspec, *outspec; + firqb outf; + firqb tmpf; + long savelbn; + int arg, j; + const char *mode; + int binmode; + char answer; + long bytes, totalbytes, files, insize; + word dirne; + byte defprot; + struct stat sbuf; + ufdrms1 rms1; + ufdrms1 *a1; + ufdrms2 rms2; + ufdrms2 *a2; + + if (argc < 2) { + printf ("Usage: %s put file... dest\n", progname); + return; + } + outspec = argv[--argc]; + if (sw.size == NULL) newsize = 0; + else { + newsize = strtoul (sw.size, &p, 10); + if (*p != '\0') { + printf ("Invalid size %s\n", sw.size); + return; + } + } + if (sw.contig == NULL && newsize != 0) { + newsize = 0; + printf ("-size switch ignored, -contiguous not specified\n"); + } + if (!parse (outspec, &outf)) { + printf ("Invalid destination spec %s\n", outspec); + return; + } + if ((outf.flags & f_name) == 0) { + for (j = 0; j < 6; j++) outf.name[j] = '?'; + outf.flags |= f_name | f_namw; + } + if ((outf.flags & f_ext) == 0) { + outf.name[7] = '?'; + outf.name[8] = '?'; + outf.name[9] = '?'; + outf.flags |= f_ext | f_extw; + } + if (sw.tree == NULL && (outf.flags & f_ppnw) != 0) { + printf ("Wildcard PPN without -tree not allowed in %s\n", + outspec); + return; + } + rmountrw (); /* mount disk R/W */ + if (sw.clusiz == NULL) newclu = pcs; + else { + newclu = strtol (sw.clusiz, &p, 10); + if (newclu < 0) { + newclu = -newclu; + if (newclu < pcs) newclu = pcs; + } + if (*p != '\0' || newclu < pcs || newclu > 128 || + (newclu & (-newclu)) != newclu) { + rumountrw (); /* remember to dismount */ + printf ("Invalid clustersize %s\n", sw.clusiz); + return; + } + } + if (sw.tree == NULL) { + if ((dirne = initfilescan (&outf, gfdatrtbl)) == 0) { + rumountrw (); /* remember to dismount */ + printf ("Account does not exist %s\n", outspec); + return; + } + readlk (dirne); + if ((savelbn = allocufd (dirne, &outf)) == 0) { /* allocate UFD if needed */ + rumountrw (); /* remember to dismount */ + printf ("No room to allocate UFD\n"); + return; + } + } + files = 0; + totalbytes = 0; + for (arg = 0; arg < argc; arg++) { + inspec = argv[arg]; /* pick up a name */ + mergename (inspec, &outf, sw.tree != NULL); + /* construct output name */ + if (outf.cproj == 0 && outf.cprog == 0) { + printf ("Bad directory spec from input filespec %s\n", inspec); + continue; + } + answer = doquery (putname, inspec); + if (answer == 'q') break; + if (answer == 'n') continue; + if (sw.ascii != NULL) binmode = FALSE; + else if (sw.bswitch != NULL) binmode = TRUE; + else binmode = !textfile (outf.cname); + if (binmode) mode = "rb"; + else mode = "r"; + if (sw.debug != NULL) printf ("put mode %s\n", mode); + if ((inf = fopen (inspec, mode)) == NULL) { + printf ("Can't open %s\n", inspec); + perror (progname); + continue; /* skip this one */ + } + if (fstat (fileno(inf), &sbuf)) { /* get info about input file */ + printf ("Can't stat input file %s", inspec); + perror (progname); + fclose (inf); /* close input */ + continue; /* and carry on */ + } + insize = UP(sbuf.st_size,BLKSIZE) / BLKSIZE; + if (sw.tree != NULL) { + memcpy (&tmpf, &outf, sizeof (firqb)); + tmpf.proj = tmpf.cproj; + tmpf.prog = tmpf.cprog; + dirne = initfilescan (&tmpf, gfdatrtbl); /* does PPN exist yet? */ + if (dirne == 0) { + if (!makedir (&outf, pcs)) { + printf ("Cannot create PPN [%d,%d]\n", + outf.cproj, outf.cprog); + fclose (inf); + continue; + } + if (plevel > RDS0) { + fbread (curgfd + gfdatrtbl); + dirne = fibufw[outf.cprog]; + readlktbl (dirne); + } else { + dirne = prevppnlink; + readlk (dirne); + } + } + if ((savelbn = allocufd (dirne, &outf)) == 0) { + printf ("No room to allocate UFD [%d,%d]\n", + outf.cproj, outf.cprog); + fclose (inf); + continue; + } + } + fbread (savelbn); /* read output directory */ + readlk2 (0); /* read UFD label */ + prevlink = 0; /* start there */ + nextlink = use(ufdlabel,0)->ulnk; /* and initialize scan */ + memcpy (&tmpf, &outf, sizeof (firqb)); + memcpy (tmpf.name, outf.cname, NAMELEN); + if (nextfileindir (&tmpf)) { /* file exists... */ + if (protfile (&tmpf)) { + fclose (inf); /* protected file, skip */ + continue; + } + if (sw.prot != NULL) { + printf ("File "); + printcurname (&tmpf); + printf (" exist, not replaced\n"); + fclose (inf); + continue; + } + delfile (&tmpf); /* now really delete the file */ + fbread (savelbn); /* read output directory */ + readlk2 (0); /* read UFD label */ + prevlink = 0; /* start there */ + nextlink = use(ufdlabel,0)->ulnk; /* and initialize scan */ + memcpy (tmpf.name, outf.cname, NAMELEN); + nextfileindir (&tmpf); /* find end of directory */ + } + outf.clusiz = newclu; + if (sw.contig == 0) outf.size = 0; + else { + if (newsize == 0) outf.size = insize; + else outf.size = newsize; + } + defprot = 60; /* default not runnable */ + if (checkrts (&outf, rtsname)) { + if (newsize >> 16) { /* if large file */ + printf ("warning: can't set rts for large file "); + printcurname (&outf); + outf.newprot &= ~up_run; /* never runnable */ + } else defprot = 124; /* default is now runnable */ + } + if ((outf.flags & f_prot) == 0) outf.newprot = defprot; + if (outf.size) outf.stat = us_nox; + else outf.stat = 0; + a1 = NULL; /* assume no attributes */ + a2 = NULL; + memset (&rms1, 0, sizeof(rms1)); /* and clear them in case */ + memset (&rms2, 0, sizeof(rms2)); + if (sw.rmsvar != NULL || sw.rmsfix != NULL || + sw.rmsstm != NULL) { + a1 = &rms1; + if (sw.rmsvar != NULL) { + a1->fa_typ = rf_var | fo_seq; + a2 = &rms2; + memset (&rms2, 0, sizeof(rms2)); + a2->fa_msz = 512; /* dummy value */ + } + if (sw.rmsstm != NULL) a1->fa_typ = rf_stm | fo_seq; + if (sw.rmsfix != NULL) { + a1->fa_typ = rf_fix | fo_seq; + a2 = &rms2; + a1->fa_rsz = strtoul (sw.rmsfix, &pp, 10); + if (*pp != '\0') a1->fa_rsz = 0; + a2->fa_msz = a1->fa_rsz; + insize = (insize / (a1->fa_rsz / BLKSIZE)) * + (a1->fa_rsz / BLKSIZE); + insize++; + } + a1->fa_siz[0] = a1->fa_eof[0] = insize >> 16; + a1->fa_siz[1] = a1->fa_eof[1] = insize & 0xffff; + a1->fa_eofb = 0; + } + if (crefile (&outf, rtsname, a1, a2)) { + bytes = putfile (inf, &outf, binmode); + if (bytes < 0 || (bytes == 0 && outf.size != 0)) { + bytes = -bytes; + printf ("Failure copying %s to ", inspec); + printcurname (&outf); + printf (" -- %ld bytes copied in ", bytes); + if (binmode) printf ("block mode\n"); + else printf ("line mode\n"); + } else if (sw.verbose) { + printf ("%s =>> ", inspec); + printcurname (&outf); + printf (" (%ld bytes) in ", bytes); + if (binmode) printf ("block mode\n"); + else printf ("line mode\n"); + } + files++; + totalbytes += bytes; + } else { + printf ("No room to create file "); + printcurname (&outf); + printf ("\n"); + } + fclose (inf); + } + if (sw.verbose != NULL) + printf ("Total files: %ld, total bytes: %ld\n", files, totalbytes); + rumountrw (); /* done with R/W disk */ +} diff --git a/extracters/rstsflx/doput.h b/extracters/rstsflx/doput.h new file mode 100644 index 0000000..53e89dc --- /dev/null +++ b/extracters/rstsflx/doput.h @@ -0,0 +1 @@ +extern void doput(int argc , char ** argv); diff --git a/extracters/rstsflx/dorename.c b/extracters/rstsflx/dorename.c new file mode 100644 index 0000000..9780299 --- /dev/null +++ b/extracters/rstsflx/dorename.c @@ -0,0 +1,96 @@ +/* handler for the "rename" command */ + +#include +#include + +#include "flx.h" +#include "fldef.h" +#include "dorename.h" +#include "fip.h" +#include "filename.h" +#include "fileio.h" +#include "scancmd.h" + +firqb newf; /* new name */ + +void renamefile (firqb *f) +{ + ufdne *n; + firqb tmpf; + word saveprev, savenext; + + if (protfile (f)) return; /* quit if file protected */ + mergename (f->cname, &newf, FALSE); + readlk2 (0); /* read UFD label */ + saveprev = prevlink; /* save current scan pointers */ + savenext = nextlink; + prevlink = 0; /* start there */ + nextlink = use(ufdlabel,0)->ulnk; /* and initialize scan */ + memcpy (&tmpf, &newf, sizeof (firqb)); + memcpy (tmpf.name, newf.cname, NAMELEN); + if (nextfileindir (&tmpf)) /* file exists... */ + { + if (f->nlink == tmpf.nlink) + { + printf ("New name matches old name "); + printcurname (f); + printf ("\n"); + return; + } + if (protfile (&tmpf)) return; /* protected file, skip */ + if (sw.replace == NULL) + { + printf ("Cannot rename "); + printcurname (f); + printf (" to %s -- file already exists\n", tmpf.name); + return; + } + delfile (&tmpf); /* now really delete the file */ + } + prevlink = saveprev; /* restore pointers */ + nextlink = savenext; + readlk (f->nlink); /* read the NE */ + n = use(ufdne,k); + cvtnameexttor50 (newf.cname, n->unam); /* write new RAD50 name into NE */ + MARKF; + upddlw (f); + if (sw.verbose != NULL) + { + printcurname (f); + printf (" renamed to %s\n", newf.cname); + } +} + +void dorename (int argc, char **argv) +{ + char *newname; + int j; + + if (--argc < 1) + { + printf ("Usage: %s rename file ... newname\n", progname); + return; + } + newf.flags = 0; /* clear parse flags */ + newname = argv[argc]; /* save name pointer */ + if (*parsenameext (newname, &newf) != '\0') + { + printf ("Invalid new name %s\n", newname); + return; + } + if ((newf.flags & f_name) == 0) + { + for (j = 0; j < 6; j++) newf.name[j] = '?'; + newf.flags |= f_name | f_namw; + } + if ((newf.flags & f_ext) == 0) + { + newf.name[7] = '?'; + newf.name[8] = '?'; + newf.name[9] = '?'; + newf.flags |= f_ext | f_extw; + } + rmountrw (); /* mount the disk */ + dofiles (argc, argv, renamefile, NOTNULL); + rumountrw (); /* done with disk */ +} diff --git a/extracters/rstsflx/dorename.h b/extracters/rstsflx/dorename.h new file mode 100644 index 0000000..f29648d --- /dev/null +++ b/extracters/rstsflx/dorename.h @@ -0,0 +1,4 @@ +extern void renamefile(firqb * f); + /* Prototype include a typedef name. + It should be moved after the typedef declaration */ +extern void dorename(int argc , char ** argv); diff --git a/extracters/rstsflx/dorts.c b/extracters/rstsflx/dorts.c new file mode 100644 index 0000000..f0c5d04 --- /dev/null +++ b/extracters/rstsflx/dorts.c @@ -0,0 +1,56 @@ +/* handler for the "rts" command */ + +#include + +#include "flx.h" +#include "fldef.h" +#include "dorts.h" +#include "fip.h" +#include "filename.h" +#include "fileio.h" +#include "scancmd.h" + +char *rtsname; /* new rts in ascii */ +word16 rtsr50[2]; /* and in rad50 */ + +void rtsfile (firqb *f) +{ + ufdae *a; + + if (protfile (f)) return; /* quit if file protected */ + readlk (f->alink); /* read the AE */ + a = use(ufdae,k); + if (a->urts[0] == 0 && a->urts[1] != 0) { + printcurname (f); + printf (" is a large file\n"); + return; + } + a->urts[0] = rtsr50[0]; + a->urts[1] = rtsr50[1]; + MARKF; + upddlw (f); + if (sw.verbose != NULL) { + printcurname (f); + printf (" rts changed to %s\n", rtsname); + } +} + +void dorts (int argc, char **argv) +{ + firqb rtsf; + + if (--argc < 1) { + printf ("Usage: %s rts file ... rts\n", progname); + return; + } + rtsf.flags = 0; /* clear parse flags */ + rtsname = argv[argc]; /* save name pointer */ + if (*parsename (rtsname, &rtsf) != '\0' || rtsf.flags != f_name) { + printf ("Invalid rts name %s\n", rtsname); + return; + } + cvtnametor50 (rtsf.name, rtsr50); + rmountrw (); /* mount the disk */ + dofiles (argc, argv, rtsfile, NOTNULL); + rumountrw (); /* done with disk */ +} diff --git a/extracters/rstsflx/dorts.h b/extracters/rstsflx/dorts.h new file mode 100644 index 0000000..702f0f6 --- /dev/null +++ b/extracters/rstsflx/dorts.h @@ -0,0 +1,4 @@ +extern void rtsfile(firqb * f); + /* Prototype include a typedef name. + It should be moved after the typedef declaration */ +extern void dorts(int argc , char ** argv); diff --git a/extracters/rstsflx/dosabsio.c b/extracters/rstsflx/dosabsio.c new file mode 100644 index 0000000..47217f2 --- /dev/null +++ b/extracters/rstsflx/dosabsio.c @@ -0,0 +1,337 @@ +/* absread and abswrite services for use with DJGPP GNU C implementation + * + * Paul Koning 94.10.16 + * 94.11.18 added bios i/o + * 94.11.21 dos i/o for hard disk, bios i/o for floppy + * 94.12.19 add retry for bios I/O + * 95.01.05 update for generalized abs i/o in flx + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "flx.h" +#include "absio.h" + +#define tb _go32_info_block.linear_address_of_transfer_buffer + +#define BIOSBUF (_go32_info_block.size_of_transfer_buffer) + /* size of djgpp bios disk I/O buffer */ +#define BIOSMAX (18 * BLKSIZE) /* max size in biosdisk() call */ +#define BIOSRESET 0 /* error reset */ +#define BIOSREAD 2 /* bios disk read function code */ +#define BIOSWRITE 3 /* bios disk write function code */ +#define BIOSTRIES 4 /* retry count */ +#define ABSREAD 0x25 /* abs read int code */ +#define ABSWRITE 0x26 /* abs write int code */ +#define BIOS_DATA_SEG 0x0040 /* BIOS data segment number */ +#define BIOS_DSK_STATE 0x0090 /* offset to drive 0 media state */ +#define DISK_STATE ((BIOS_DATA_SEG << 4) + BIOS_DSK_STATE) + +#define BIOS_DSK_360K 0x74 /* 360kb media established */ +#define BIOS_DSK_RX50 0x54 /* RX50 media established in drive */ + /* (same as 360kb except single steps */ + /* for 96 tpi media) */ + +static int secsize = 0; +static int param_segment = 0; +static int rx_segment; +static _go32_dpmi_seginfo oldvec; +static _go32_dpmi_seginfo rx50table_vec; +static unsigned short int dosparam[5]; +static int rxflag = 0; /* set if accessing 5.25 inch floppy */ +static int gdrive = -1; /* drive to which geometry data applies */ +static int drive; /* disk unit number currently open */ +static int sectors, heads, cylinders, drives; +static _go32_dpmi_seginfo param_info; + +/* + * Disk parameter table for RX50 floppies in 1.2MB drive + * (set INT 1Eh vector to point to this) + */ +static byte dparm[] = { 0xDF,0x02, /* "specify" cmd bytes */ + 0x25, /* motor turn-on time */ + 2,10, /* 512 b/s, 10 sec/tk */ + 20, /* gap length */ + -1, /* max transfer */ + 24, /* gap length (format) */ + 0xE5, /* fill byte (format) */ + 15, /* head settle time (ms) */ + 8 }; /* motor start time (1/8 sec) */ + +/* The param_buffer is used for two things: + * 1. to hold the dos abs disk I/O parameter block + * 2. to hold the rx50 disk parameter table data + * We put both into the same buffer, in separate segments. + */ + +static void free_param_buffer() +{ + _go32_dpmi_free_dos_memory(¶m_info); + param_segment = 0; +} + +static void alloc_param_buffer() +{ + if (param_segment) return; + param_info.size = (UP(sizeof(param_info),16) + + UP(sizeof(dparm),16)) / 16; + if (_go32_dpmi_allocate_dos_memory(¶m_info)) { + param_segment = 0; + return; + } + param_segment = param_info.rm_segment; + rx_segment = param_segment + UP(sizeof(param_info),16) / 16; + dosmemput(dparm, sizeof(dparm), rx_segment << 4); + rx50table_vec.rm_segment = rx_segment; + rx50table_vec.rm_offset = 0; + atexit(free_param_buffer); +} + +/* convert dos style drive number to bios style number */ + +static int biosdrive (int drive) +{ + if (drive < 3) return (drive - 1); + else return ((drive - 3) + 0x80); /* need to do partitions */ +} + +/* do bios I/O with retries */ + +static int biosdiskr (int func, int drive, int track, int cyl, + int sec, int count, void *buffer) +{ + int tries, status; + + for (tries = 0; tries < BIOSTRIES; tries++) { + status = biosdisk (func, biosdrive (drive), track, cyl, + sec, count, buffer); + if (status == 0) break; + + /* strictly speaking one should do error classification + * at this point... + */ + biosdisk (BIOSRESET, biosdrive (drive), 0, 0, 0, 0, NULL); + } + return (status); +} + +static void getgeom (int drive) +{ + byte status[4]; + + gdrive = drive; + biosdisk (8, biosdrive (drive), 0, 0, 0, 1, status); + heads = status[3] + 1; + drives = status[2]; + cylinders = status[1] + ((status[0] >> 6) << 8) + 1; + sectors = status[0] & 0x3f; + if (status[0] == 15 && status[1] == 79 & status[3] == 1) + rxflag = 1; + else rxflag = 0; +} + +/* Convert block number to cylinder, head, sector for RT11-RX50. + * This is different for RT11 than for Rainbow DOS: + * For DOS, for cylinders 2 through 79, the sectors are interleaved 2:1. + * (DOS capability is not supported in this RT11 version). + * For RT11, all sectors are interleaved 2:1, and each subsequent + * track has the first logical block offset by 2 more sectors. + */ + +static void makechs_rx50 (int block, int *trk, int *sec) +{ + int t, s; + + t = block / 10; + s = block % 10 + 1; + if (s < 6) s = (s - 1) * 2 + 1; + else s = (s - 5) * 2; + s += t * 2; + while (s > 10) s -= 10; + t++; + if (t == 80) t = 0; /* wrap around last 10 blocks */ + *trk = t; + *sec = s; +} + +/* do single block disk I/O to DEC RX50 floppy */ +static int rx50io (int func, int drive, int dsksec, void *buffer) +{ + byte oldstate; + byte newstate = BIOS_DSK_RX50; + int cyl, sec; + int status; + + alloc_param_buffer(); + + /* save old state and set up for RX50 I/O */ + _go32_dpmi_get_real_mode_interrupt_vector (0x1E, &oldvec); + _go32_dpmi_set_real_mode_interrupt_vector (0x1E, &rx50table_vec); +#ifdef NOT + dosmemget (DISK_STATE, 1, &oldstate); + dosmemput (&newstate, 1, DISK_STATE); +#endif + + makechs_rx50 (dsksec, &cyl, &sec); + status = biosdiskr (func, drive, 0, cyl, sec, 1, buffer); + + /* restore BIOS state as it was on entry */ + _go32_dpmi_set_real_mode_interrupt_vector (0x1E, &oldvec); +#ifdef NOT + dosmemput (&oldstate, 1, DISK_STATE); +#endif + return (status); +} + +/* do bios disk I/O call + * if this is a 5.25" floppy, we do the required magic to read it as + * a DEC RX50 format floppy. + */ + +static int biosio (int func, int drive, int dsksec, int count, void *buffer) +{ + int track, sec, cyl; + int tcount, status; + + if (drive != gdrive) getgeom (drive); + while (count) { + if (rxflag) { + tcount = BLKSIZE; + status = rx50io (func, drive, dsksec, buffer); + } else { + tcount = count; + if (tcount > BIOSMAX) tcount = BIOSMAX; + sec = dsksec % sectors; + if ((sectors - sec) * BLKSIZE < tcount) + tcount = (sectors - sec) * BLKSIZE; + sec++; /* weird 1-based numbering */ + track = (dsksec / sectors) % heads; + cyl = dsksec / (sectors * heads); + status = biosdiskr (func, drive, track, cyl, + sec, tcount / BLKSIZE, buffer); + } + if (status) return (status); + count -= tcount; + buffer += tcount; + dsksec += (tcount / BLKSIZE); + } + return (0); +} + +/* do absolute dos disk read/write + * arguments: + * function code (0x25 = read, 0x26 = write) + * drive number (1 = a:, etc) + * starting sector number + * byte count (must be multiple of sector size) + * buffer pointer + */ + +static int dosio (int func, int drive, int sec, int count, void *buffer) +{ + int bseg, bofs, xfer=0, before=0, tcount; + _go32_dpmi_registers r; + + while (count) { + tcount = count; + if (tcount > BIOSBUF) tcount = BIOSBUF; + alloc_param_buffer(); + dosparam[0] = sec & 0xffff; + dosparam[1] = sec >> 16; + dosparam[2] = (tcount / secsize) & 0xffff; + dosparam[3] = (unsigned int) tb & 15; + dosparam[4] = (unsigned int) tb >> 4; + dosmemput(dosparam, sizeof(dosparam), param_segment << 4); + if (func == ABSWRITE) + dosmemput(buffer, tcount, tb); + memset(&r, 0, sizeof(r)); + r.h.al = drive - 1; /* 0-based numbering here */ + r.x.ds = param_segment; + r.x.bx = 0; + r.x.cx = -1; + _go32_dpmi_simulate_int(func, &r); + if (func == ABSREAD) + dosmemget(tb, tcount, buffer); + if (r.x.flags & 1) + return (r.h.al); + count -= tcount; + buffer += tcount; + sec += (tcount / secsize); + } + return (0); +} + +/* return size of specified disk, in blocks. Saves sector size in a local + * static variable as a side effect. A flag is set if the disk is a + * 5.25 inch floppy. + * Note: this must be called before any abs I/O is done. + */ + +static int disksize (int drive) +{ + _go32_dpmi_registers r; + byte mid; + + if (drive >= 3) { /* hard disk */ + memset(&r, 0, sizeof(r)); + r.h.ah = 0x1c; + r.h.dl = drive; + _go32_dpmi_simulate_int(0x21, &r); + secsize = r.x.cx; + return (r.h.al * r.x.dx * secsize / BLKSIZE); + } else { + getgeom (drive); + secsize = 512; + return (cylinders * heads * sectors); + } +} + +/* this routine is called to scan a supplied container file/device + * name. If the name refers to a real disk, then absflag is set + * and rsize is set to the device size. Otherwise, no action is taken. + */ + +void absname (const char *rname) +{ + if (rname[strlen(rname) - 1] == ':') { /* device name alone */ + absflag = TRUE; + drive = tolower (rname[0]) - 'a' + 1; /* set drive number */ + rsize = disksize (drive); + if (sw.debug != NULL) + printf ("disk size for drive %d is %d\n", drive, rsize); + } +} + +int absopen (const char *rname, const char *mode) +{ + return (0); /* always ok, nothing to do */ +} + +void absseek (int block) { } /* nothing to do */ + +void absclose () { } /* nothing to do */ + +int absread (int sec, int count, void *buffer) +{ + if (drive >= 3) /* hard disk */ + return (dosio (ABSREAD, drive, sec, count, buffer)); + else + return (biosio (BIOSREAD, drive, sec, count, buffer)); +} + +int abswrite (int sec, int count, void *buffer) +{ +#ifdef NOT_YET + if (drive >= 3) /* hard disk */ + return (dosio (ABSWRITE, drive, sec, count, buffer)); + else + return (biosio (BIOSWRITE, drive, sec, count, buffer)); +#endif +} + diff --git a/extracters/rstsflx/dosabsio.h b/extracters/rstsflx/dosabsio.h new file mode 100644 index 0000000..1f1355e --- /dev/null +++ b/extracters/rstsflx/dosabsio.h @@ -0,0 +1,3 @@ +extern int absread (int drive, int sec, int count, void *buffer); +extern int abswrite (int drive, int sec, int count, void *buffer); +extern int disksize (int drive); diff --git a/extracters/rstsflx/dosrxio.c b/extracters/rstsflx/dosrxio.c new file mode 100644 index 0000000..1082abd --- /dev/null +++ b/extracters/rstsflx/dosrxio.c @@ -0,0 +1,203 @@ +/* floppy disk I/O for DOS + * + * based on RXRTDVRA.ASM by Robert Morse and John Dudeck + */ + +/* --------------------------------------------------------------- + * IBM ROM BIOS Definitions + * --------------------------------------------------------------- + */ + +#define DKOP_RUPT 013h /* interrupt to call ROM BIOS */ +#define DKOP_RESET 000h /* reset controller */ +#define DKOP_STATUS 001h /* read status from last operation */ +#define DKOP_READ 002h /* read sectors */ +#define DKOP_WRITE 003h /* write sectors */ +#define DKOP_VERIFY 004h /* verify sectors */ +#define DKOP_CHANGE 016h /* test changed status */ +#define DKOP_SETTYPE 017h /* set media type in drive */ + +#define DKST_TIMEOUT 080h /* drive not ready */ +#define DKST_BADSEEK 040h /* seek failed */ +#define DKST_BADNEC 020h /* NEC controller failed */ +#define DKST_BADCRC 010h /* read CRC error */ +#define DKST_BADDMA 009h /* attempt to DMA over 64K boundary */ +#define DKST_OVERRUN 008h /* DMA overrun */ +#define DKST_CHANGED 006h /* media changed */ +#define DKST_RNF 004h /* sector not found */ +#define DKST_WRPROT 003h /* write-protected diskette */ +#define DKST_ADRMARK 002h /* address mark not found */ +#define DKST_BADCMD 001h /* invalid command */ + + +#define BIOS_DATA_SEG 0040h + +/* #define BIOSDATA segment at BIOS_DATA_SEG /* BIOS data segment-- */ + +#define bios_dsk_state (*(byte *)(0x0090)) /* drive 0 media state */ + +#define BIOS_DSK_360K 074h /* 360kb media established */ +#define BIOS_DSK_RX50 054h /* RX50 media established in drive */ + /* (same as 360kb except single steps */ + /* for 96 tpi media) */ + +/* Convert block number to cylinder, head, sector for RT11-RX50. + * This is different for RT11 than for Rainbow DOS: + * For DOS, for cylinders 2 through 79, the sectors are interleaved 2:1. + * (DOS capability is not supported in this RT11 version). + * For RT11, all sectors are interleaved 2:1, and each subsequent + * track has the first logical block offset by 2 more sectors. + */ + +void makechs_rx50 (int block, int *trk, int *sec) +{ + int t, s; + + t = block / 10; + s = block % 10 + 1; + if (s < 6) s = (s - 1) * 2 + 1; + else s = (s - 5) * 2; + s += t * 2; + while (s > 10) s -= 10; + t++; + *trk = t; + *sec = s; +} + +;Common routine for read, write and verify. +; +;Given: AL = operation code +; ES:DI = pointer to IOP, which contains +; iop_block = starting block number +; iop_bufptr = starting buffer address +; iop_count = number of blocks +;Returns: AX = IOP error code +; xx_count = number of requested blocks NOT transferred + +do_readwrite: + mov es:iop_rwvoloff[di], offset vol_name + mov es:iop_rwvolseg[di], cs + + mov xx_oper, al ;save operation code + + mov ax, es:iop_block[di] ;set starting block number + + test ax, ax ;JRD check for negative + jge do_rw1 ;JRD + xor ax, ax ;JRD +do_rw1: + push si ;JRD + mov si, bpb_pointer ;JRD + cmp ax, bpb_totsects[si] ;JRD test for too big + jle do_rw2 ;JRD + mov ax, bpb_totsects[si] ;JRD limit to maximum +do_rw2: + pop si ;JRD + + mov xx_block, ax + mov ax, es:iop_count[di] ;set block count + mov xx_count, ax + test ax, ax + jz dorw_success ; quit if 0 sectors to do + + mov ax, es:iop_bufoff[di] ;set starting buffer offset + mov xx_offset, ax ; and segment + mov ax, es:iop_bufseg[di] + mov xx_seg, ax + +dorw_loop: + mov xx_retries, 5 ;set retry counter +dorw_again: + mov ax, BIOS_DATA_SEG ;set diskette status to single + mov es, ax ; stepping for 96 tpi + mov es:bios_dsk_state, BIOS_DSK_RX50 + + mov ax, xx_block ;load block number + call makechs_rx50 ; and convert to CHS + mov dl, PHYS_DRIVE_0 ;set drive number + mov ah, xx_oper ;operation code + mov al, 1 ;transfer 1 sector + les bx, xx_buf ;set ES:BX to buffer address + int DKOP_RUPT ;invoke ROM BIOS to do it + mov xx_status, ah ; and save returned status + test ah, ah ;test for error + jnz dorw_error ; break loop on error + + inc xx_block ;advance to next block + add xx_offset, PHYS_BLKSIZE ;advance buffer pointer + dec xx_count ;count blocks + jnz dorw_loop ; and continue until done +dorw_success: + xor ax, ax ;set no-error code + ret + ;Analyze read/write errors and either make another attempt or +;set the error code and return. + +dorw_error: + mov al, IOPST_NOTRDY + test ah, DKST_TIMEOUT + jnz dorw_giveup + + mov al, IOPST_SEEK + test ah, DKST_BADSEEK + jnz dorw_retry + + mov al, IOPST_IOERR + test ah, DKST_BADNEC + jnz dorw_retry + + cmp ah, DKST_OVERRUN + je dorw_retry + + mov al, IOPST_CRC + cmp ah, DKST_BADCRC + je dorw_retry + + mov al, IOPST_BADCMD + cmp ah, DKST_BADDMA + je dorw_giveup + + cmp ah, DKST_BADCMD + je dorw_giveup + + mov al, IOPST_BADCHNG + cmp ah, DKST_CHANGED + jne dorw_nochange + cmp open_count, 0 + jg dorw_giveup ;error if change with any files open + jmp short dorw_reset ; else do it again +dorw_nochange: + mov al, IOPST_RNF + cmp ah, DKST_RNF + je dorw_retry + + mov al, IOPST_WRPROT + cmp ah, DKST_WRPROT + je dorw_giveup + + mov al, IOPST_UNKMEDIA + cmp ah, DKST_ADRMARK + je dorw_retry + + mov al, IOPST_IOERR + jmp short dorw_giveup +dorw_retry: + dec xx_retries ;count retries + jle dorw_giveup +dorw_reset: + mov ah, DKOP_RESET ;reset the disk controller + int DKOP_RUPT + jmp dorw_again ; and try again +dorw_giveup: + mov ah, high IOPST_ERR ;complete the driver error return code + ret + +int rxread (int block, int size, void *buffer) +{ + return (rxio (DKOP_READ, block, size, buffer)); +} + +int rxwrite (int block, int size, void *buffer) +{ + return (rxio (DKOP_WRITE, block, size, buffer)); +} diff --git a/extracters/rstsflx/dotype.c b/extracters/rstsflx/dotype.c new file mode 100644 index 0000000..27cb5c6 --- /dev/null +++ b/extracters/rstsflx/dotype.c @@ -0,0 +1,28 @@ +/* handler for the "type" command */ + +#include + +#include "flx.h" +#include "fldef.h" +#include "dotype.h" +#include "fip.h" +#include "filename.h" +#include "fileio.h" +#include "scancmd.h" + +void typefile (firqb *f) +{ + if (sw.verbose != NULL) { + printf ("\n----- "); + printcurname (f); + printf (" -----\n"); + } + getfile (stdout, f, FALSE); /* put it on stdout */ +} + +void dotype (int argc, char **argv) +{ + rmount (); /* mount the disk */ + dofiles (argc, argv, typefile, NOTNULL); + rumount (); /* done with disk */ +} diff --git a/extracters/rstsflx/dotype.h b/extracters/rstsflx/dotype.h new file mode 100644 index 0000000..9c7ba98 --- /dev/null +++ b/extracters/rstsflx/dotype.h @@ -0,0 +1,4 @@ +extern void typefile(firqb * f); + /* Prototype include a typedef name. + It should be moved after the typedef declaration */ +extern void dotype(int argc , char ** argv); diff --git a/extracters/rstsflx/fdprm b/extracters/rstsflx/fdprm new file mode 100644 index 0000000..0cd6030 --- /dev/null +++ b/extracters/rstsflx/fdprm @@ -0,0 +1,29 @@ +# /etc/fdprm - floppy disk parameter table + +# Common disk formats. Names are of the form +# actual media capacity/maximum drive capacity +# (Note: although 5.25" HD drives can format disks at 1.44M, they're listed +# as 1200 because that's the common maximum size.) + +# size sec/t hds trk stre gap rate spec1 fmt_gap +360/360 720 9 2 40 0 0x2A 0x02 0xDF 0x50 +1200/1200 2400 15 2 80 0 0x1B 0x00 0xDF 0x54 +360/720 720 9 2 40 1 0x2A 0x02 0xDF 0x50 +720/720 1440 9 2 80 0 0x2A 0x02 0xDF 0x50 +720/1440 1440 9 2 80 0 0x2A 0x02 0xDF 0x50 +360/1200 720 9 2 40 1 0x23 0x01 0xDF 0x50 +720/1200 1440 9 2 80 0 0x23 0x01 0xDF 0x50 +1440/1440 2880 18 2 80 0 0x1B 0x00 0xCF 0x6C + +# Non-standard disk formats: + +# BEWARE: They're incomplete and possibly incorrect. The only reason why +# they are in this file is to show how such formats are added. + +1440/1200 2880 18 2 80 0 ???? ???? ???? ???? # ????? +1680/1440 3360 21 2 80 0 0x0C 0x00 0xCF 0x6C # ????? + +# Add user-specific formats here +cbm1581 1600 10 2 80 2 0x2A 0x02 0xDF 0x2E +800/720 1600 10 2 80 0 0x2A 0x02 0xDF 0x2E +rx50 800 10 1 80 0 0x23 0x01 0xDF 0x50 diff --git a/extracters/rstsflx/fileio.c b/extracters/rstsflx/fileio.c new file mode 100644 index 0000000..3775620 --- /dev/null +++ b/extracters/rstsflx/fileio.c @@ -0,0 +1,592 @@ +/* subroutines to do rsts file (virtual block) I/O */ + +#include +#include +#include + +#include "flx.h" +#include "fldef.h" +#include "fileio.h" +#include "filename.h" +#include "diskio.h" +#include "fip.h" + +long totalbytes; /* total bytes transferred for get/put */ +long curvbn; /* current file vbn (0-based) */ +word curre; /* link of current RE */ +word lastre; /* and last one seen */ +int curreoff; /* offset into current RE */ +int cluoff; /* offset into current file cluster */ +int dcnperfcs; /* fcs / dcs */ + + +static int rmseof (firqb *f, char *recp, long iocount) +{ + long curblk; + int curbyt; + + curblk = curvbn + (recp - iobuf - iocount) / BLKSIZE; + curbyt = (recp - iobuf) % BLKSIZE; + if (curblk > f->eofblk) return (TRUE); + return (curblk == f->eofblk && curbyt >= f->eofbyte); +} + +/* in each of the following "get a record" routines (one for each record + * format defined for RMS-11) the arguments are: + * f pointer to firqb struct + * len pointer to record length return variable + * eor pointer to end of record return variable (flag) + * iocount amount of data in I/O buffer (from last seqio call) + * + * len is set to the length of the record or partial record returned. + * the pointer to the record is the return value of the function. + * eor is set true if a whole record was transferred, and false if only + * a partial record is returned. (If eor is set, then a line delimiter + * should be added by the caller if it is not contained in the record + * itself.) + * If nothing was transferred (i.e., the caller should retry) then + * these functions return NULL. Otherwise they return a record pointer. + * Note that in the latter case the length may be zero, which means + * the record was an empty line. + */ + +static char *getfix (firqb *f, long *len, int *eor, long iocount) +{ + long left; /* amount left in I/O buffer */ + char *recp; + + recp = f->currec; + left = &iobuf[iocount] - recp; /* compute what's left */ + *eor = FALSE; /* default to not EOR */ + if (left <= 0 || rmseof (f, recp, iocount)) { + *len = 0; + f->currec = NULL; + return (NULL); + } + if (left < f->recsiz) { + *len = left; + f->currec = NULL; + return (recp); + } + *len = f->recsiz; + f->currec += f->recsiz; + *eor = TRUE; + return (recp); +} + +static char *getvar (firqb *f, long *len, int *eor, long iocount) +{ + char *recp; + word16 reclen; + word16 *reclenp; + long left; + + recp = f->currec; + *eor = FALSE; /* default to not EOR */ + left = (&iobuf[iocount] - recp); + if (left <= 0 || rmseof (f, recp, iocount)) { + *len = 0; + f->currec = NULL; + f->currecsiz = 0; + return (NULL); + } + if ((reclen = f->currecsiz) == 0) { + reclenp = (word16 *)recp; + reclen = *reclenp; + if (reclen == 0xffff) { /* end of data in block */ + left &= -BLKSIZE; /* get what's left in remaining blocks */ + if (left == 0) { + *len = 0; + f->currec = NULL; + f->currecsiz = 0; + return (NULL); + } else { + recp = &iobuf[iocount - left]; + reclenp = (word16 *) recp; + reclen = *reclenp; + } + } + left -= 2; /* discount length field */ + recp += 2; /* and skip it */ + } + if (reclen > left) { + *len = left; + f->currecsiz = reclen - left; /* do this next time */ + f->currec = NULL; + return (recp); + } + f->currec = recp + UP(reclen,2); /* point to where next count is */ + f->currecsiz = 0; /* no partial record left to do */ + *len = reclen; + *eor = TRUE; + return (recp); +} + +static char *getvfc (firqb *f, long *len, int *eor, long iocount) +{ + char *recp; + word16 reclen; + word16 *reclenp; + long left, skip; + + recp = f->currec; + *eor = FALSE; /* default to not EOR */ + left = (&iobuf[iocount] - recp); + if ((reclen = f->currecsiz) != 0) skip = f->recskip; + else { + reclenp = (word16 *)recp; + reclen = *reclenp; + if (reclen == 0xffff) { /* end of data in block */ + left &= -BLKSIZE; /* get what's left in remaining blocks */ + if (left == 0) { + *len = 0; + f->currec = NULL; + f->currecsiz = 0; + return (NULL); + } else { + recp = &iobuf[iocount - left]; + reclenp = (word16 *) recp; + reclen = *reclenp; + } + } + left -= 2; /* discount length field */ + recp += 2; /* and skip it */ + skip = f->rechdrsiz; /* skip over whole header */ + } + if (reclen > left) { + f->currecsiz = reclen - left; /* do this next time */ + if (left > skip) { + *len = left - skip; + f->recskip = 0; /* nothing to skip */ + f->currec = NULL; + return (recp + skip); + } else { + *len = 0; + f->recskip = skip - left; + return (NULL); + } + } + f->currec = recp + UP(reclen,2); /* point to where next count is */ + f->currecsiz = 0; /* no partial record left to do */ + *len = reclen - skip; + *eor = TRUE; + return (recp + skip); +} + +static char *getstm (firqb *f, long *len, int *eor, long iocount) +{ + char *lfpos; + char *recp; + + *eor = FALSE; /* default to not EOR */ + while (f->currec < &iobuf[iocount]) + if (*(f->currec)) break; + else f->currec++; /* skip nulls */ + if (f->currec == &iobuf[iocount]) { + *len = 0; + f->currec = NULL; + return (NULL); + } + lfpos = (char *) memchr (f->currec, 012, &iobuf[iocount] - f->currec); + recp = f->currec; + if (lfpos == NULL || lfpos == f->currec) { + *len = &iobuf[iocount] - f->currec; + *eor = FALSE; + f->currec = NULL; + } else { + if (*(lfpos - 1) == '\015') *len = lfpos - f->currec - 1; + else *len = lfpos - f->currec; + *eor = TRUE; + f->currec = lfpos + 1; + } + return (recp); +} + +/* note that a partial record may be returned; if so, eor is set to false */ + +static char *getrec (firqb *f, long *len, int *eor, long iocount) /* get next text record */ +{ + switch (f->recfmt & fa_rfm) { + case rf_udf: + case rf_stm: + return (getstm (f, len, eor, iocount)); + case rf_fix: + return (getfix (f, len, eor, iocount)); + case rf_var: + return (getvar (f, len, eor, iocount)); + case rf_vfc: + return (getvfc (f, len, eor, iocount)); + } + rabort (INTERNAL); /* should never get here */ + return (NULL); /* to make the compiler happy */ +} + +/* Routine to do sequential I/O, either read or write according to the + * third argument passed. + */ +long seqio (firqb *f, long iolen, iohandler io, void *buffer) +{ + long startlbn; /* lbn at which to start transfer */ + long count; /* and byte count */ + word prevdcn = 0; /* previous RE entry */ + + if (curvbn >= f->size) return (0); /* nothing left */ + for (count = 0; ; ) { + if (cluoff == 0) { + if (curreoff == 0 && (f->stat & us_ufd) == 0) { + if (!readlk (curre)) rabort(BADRE); + lastre = curre; + } + if (count != 0) { + if (f->stat & us_ufd) { + if (clumap->uent[curreoff] - prevdcn != dcnperfcs) + break; + } else { + if (use(ufdre,k)->uent[curreoff] - prevdcn != dcnperfcs) + break; + } + } + if (sw.debug != 0) + printf ("seqio() RE entry %o\n", use(ufdre,k)->uent[curreoff]); + } + if (count++ == 0) { + if (f->stat & us_ufd) + startlbn = dcntolbn(clumap->uent[curreoff]) + + cluoff; + else startlbn = dcntolbn(use(ufdre,k)->uent[curreoff]) + + cluoff; + if (sw.debug != NULL) + printf ("seqio() start lbn %lo\n", startlbn); + } + /* contiguous file is treated as having one giant cluster... */ + if (++cluoff == f->clusiz && ((f->stat & us_nox) == 0)) { + cluoff = 0; + prevdcn = use(ufdre,k)->uent[curreoff]; + curreoff++; /* on to the next RE entry */ + if (curreoff == 7) { /* time to read anothe RE */ + if (f->stat & us_ufd) curre = 0; + else curre = use(ufdre,k)->ulnk; + curreoff = 0; + } + } + if (count == iolen / BLKSIZE || curvbn + count == f->size) break; + } + (*io) (startlbn, count * BLKSIZE, buffer); + curvbn += count; /* account for what we transferred */ + return (count * BLKSIZE); /* and return the byte count */ +} + +void openfile (firqb *f) /* set up file I/O at VBN 0 */ +{ + curvbn = 0; /* currently at first block */ + lastre = 0; /* working on first RE */ + curre = f->rlink; /* set current RE link */ + curreoff = 0; /* working on RE entry 0 */ + cluoff = 0; /* and start of that cluster */ +/* note: on big disks (dcs > 16) dcnperfcs will end up 0 for directories. + * that's fine; the result is that no transfer that crosses retrieval + * entries will be done in a single I/O -- exactly what we want. + */ + dcnperfcs = f->clusiz / dcs; /* how many dcn's in file cluster */ + if (f->size) /* read first RE if non-null */ + if ((f->stat & us_ufd) == 0 && !readlk (f->rlink)) + rabort(BADRE); +} + +word *relist = NULL; /* list of pointers to RE's */ + +void initrandom (firqb *f) +{ + long recount; + + if (relist != NULL) free (relist); + if (f->stat & us_ufd) return; /* UFDs are easy */ + openfile (f); /* first do common setup */ + /* Note: do not use UP() here since we don't round to + * a power of 2! + */ + recount = (f->size + 7 * f->clusiz - 1) / (7 * f->clusiz); + if ((relist = (word *) malloc (recount * sizeof (word))) == NULL) + rabort(NOMEM); + memset (relist, 0, recount * sizeof (word)); + relist[0] = f->rlink; +} + +void fileseek (firqb *f, long vbn) /* seek to (0-based) vbn */ +{ + int clu, re, renum; + word prevre; + + if (vbn >= f->size) rabort(INTERNAL); + clu = vbn / f->clusiz; /* get cluster number */ + if ((f->stat & us_ufd) == 0) { /* more work for non-UFDs */ + renum = clu / 7; /* get RE number */ + if (relist[renum] == 0) { /* load RE list if we haven't been here */ + for (re = 0; re <= renum; re++) { + if (relist[re]) prevre = relist[re]; + else { + if (!readlk (prevre)) rabort(CORRUPT); + relist[re] = prevre = use(ufdre,k)->ulnk; + } + } + } + readlk (curre = relist[renum]); /* read appropriate RE */ + } + curreoff = clu % 7; /* set index into RE */ + cluoff = vbn % f->clusiz; /* and offset into cluster */ + curvbn = vbn; /* and finally, current vbn */ +} + +/* get a RSTS file and copy it to a specified local file. Transfers in + * binary (block) mode or ascii (record) mode according to the third + * argument. The return value is the count of bytes transferred. + */ + +long getfile (FILE *to, firqb *f, int binary) +{ + long reclen, iocount; + int eor; + char *recp; + + if (f->size == 0) return (0); /* null file, nothing transferred */ + openfile (f); /* set up file transfer */ + totalbytes = 0; + if (binary) { + while ((iocount = seqio (f, iobufsize, rread, iobuf)) != 0) { + fwrite (iobuf, 1, iocount, to); + totalbytes += iocount; + } + } else { + iocount = seqio (f, iobufsize, rread, iobuf); /* do initial buffer fill */ + f->currec = iobuf; /* init current record pointer */ + f->currecsiz = 0; /* no current record size */ + while (TRUE) { + recp = getrec (f, &reclen, &eor, iocount); + if (recp != NULL) { + totalbytes += reclen; + if (reclen) fwrite (recp, 1, reclen, to); + if (eor) { + fputc ('\n', to); +#if (defined(__MSDOS__) && !defined(__unix__)) + totalbytes += 2; +#else + totalbytes++; +#endif + } + } + if (f->currec == NULL) { + if ((iocount = seqio (f, iobufsize, rread, iobuf)) == 0) + break; + else f->currec = iobuf; /* init current record pointer */ + } + } + } + return (totalbytes); +} + +/* extend the currently open file to the specified size, if not already + * that big. + */ + +long extfile (firqb *f, long blocks) +{ + int clus, reoff, clunum; + word re; + + if (sw.debug != NULL) + printf ("extfile(,%ld) from %ld\n", blocks, f->size); + if (f->size >= blocks) return (TRUE); /* already big enough */ + if (f->stat & us_nox) return (FALSE); /* error if contiguous */ + clus = (UP(blocks,f->clusiz) - UP(f->size,f->clusiz)) / f->clusiz; + if (clus == 0) { /* no new clusters needed */ + f->size = blocks; /* so just do it */ + return (TRUE); + } + if (cluoff == 0) reoff = curreoff; + else { + reoff = curreoff + 1; + if (reoff > 6) reoff = 0; /* overflowed current RE */ + } + f->size = UP(f->size,f->clusiz); /* round up to full cluster */ + while (clus > 0) { /* allocate what we need */ + if (reoff == 0) { /* need to start new RE */ + if ((re = getent ()) == 0) return (FALSE); + if (NULLINK(curre)) curre = re; /* this is now current */ + readlk (re); /* read it */ + use(ufdre,k)->ulnk = 1; /* mark it allocated */ + MARKF; + if (lastre) { /* link it to earlier RE */ + readlk (lastre); + use(ufdre,k)->ulnk = re; + } else { /* link first RE to NE */ + readlk (f->nlink); + use(ufdne,k)->uar = re; + f->rlink = re; /* record in firqb also */ + } + MARKF; + lastre = re; /* this is now the last RE */ + readlk (re); /* read the new RE */ + } + if ((clunum = getclu (f->clusiz, f->clusiz)) == 0) return (FALSE); + use(ufdre,k)->uent[reoff] = clunum; + MARKF; + f->size += f->clusiz; /* adjust file size */ + reoff++; + if (reoff > 6) reoff = 0; /* overflowed current RE */ + clus--; /* any clusters left to do? */ + } + f->size = blocks; /* it worked, all done */ + readlk (curre); /* make sure we have the right RE */ + return (TRUE); /* return with success */ +} + +/* read a local file and put it to a specified RSTS file. Transfers in + * binary (block) mode or ascii (record) mode according to the third + * argument. The return value is the count of bytes transferred if the + * copy completed, or the negative of what was transferred if the transfer + * did not finish (i.e., due to no room on the disk). + */ + +/* writefile is a support routine that writes some number of bytes from iobuf + * to the rsts output file. It returns FALSE if the write did not finish, e.g., + * due to lack of disk space. + */ + +long writefile (firqb *f, long count) +{ + long offset, blocks, wcount; + + if (sw.debug != NULL) printf ("writefile(,%ld)\n", count); + count = UP(count,BLKSIZE); + offset = 0; + blocks = (totalbytes + count) / BLKSIZE; + extfile (f, blocks); /* extend if needed */ + while (count) { + wcount = seqio (f, count, rwrite, iobuf + offset); + if (wcount == 0) { + totalbytes = -totalbytes; + return (FALSE); + } + offset += wcount; + totalbytes += wcount; + count -= wcount; + } + return (TRUE); /* write suceeded */ +} + +long putfile (FILE *from, firqb *f, int binary) +{ + long blocks, wcount, iocount, iocount2, adjust; + long oldsize, offset; + long ilen, llen; + char *iptr, *eol; + ufdne *n; + ufdae *a; + + openfile (f); /* set up file transfer */ + totalbytes = 0; + if (binary) { + while ((iocount = fread (iobuf, 1, iobufsize, from)) != 0) { + iocount2 = UP(iocount, BLKSIZE); + adjust = iocount2 - iocount; + if (adjust) memset (iobuf + iocount, 0, adjust); + if (!writefile (f, iocount2)) break; + if (adjust) { + totalbytes -= adjust; + break; /* short read, done with file */ + } + } + } else { + iptr = iobuf; /* start getting lines at the start */ + ilen = iobufsize + 2; /* use all including 2 extra bytes */ + for ( ; ; ) { + if (fgets (iptr, ilen, from) == NULL) break; + llen = strlen (iptr); /* get length of this line */ + eol = iptr + llen; /* point to terminator */ + if (*--eol == '\n') { /* if we got a complete line */ + if (*(eol - 1) == '\r') { /* terminator = cr-lf? */ + eol++; /* next line starts here */ + } else { /* only \n at eol */ + *eol++ = '\r'; /* put in the cr */ + *eol++ = '\n'; /* and overwrite null with lf */ + llen ++; /* account for cr */ + } + } else eol++; /* skip to end of data */ + iptr = eol; /* advance read ptr */ + ilen -= llen; /* compute space left */ + if (ilen <= 2) { /* full buffer */ + if (!writefile (f, iobufsize)) { + ilen = 0; /* don't write more */ + break; /* quit this file */ + } + iptr = iobuf; /* reinit pointer */ + ilen = 2 - ilen; /* # bytes to move */ + eol = iobuf + iobufsize; /* move from here */ + for ( ; ilen > 0; ilen--) *iptr++ = *eol++; + ilen = iobufsize + 2 - (iptr - iobuf); + } + } + ilen = iptr - iobuf; /* get amount buffered */ + adjust = UP(ilen,BLKSIZE) - ilen; /* get amount to pad */ + if (adjust) memset (iptr, 0, adjust); /* do it */ + iptr += adjust; /* point past it */ + if (iptr != iobuf) writefile (f, iptr - iobuf); /* write pending data */ + totalbytes -= adjust; /* don't report pad */ + } + readlk (f->alink); /* read file's AE */ + a = use(ufdae,k); + oldsize = a->usiz; /* get old file size */ + if (a->urts[0] == 0) oldsize += a->urts[1] >> 16; + if (f->size != oldsize ) { /* size changed */ + if (f->size < oldsize) rabort(INTERNAL); /* can't shrink */ + updqb (f, UP(f->size,f->clusiz) - UP(oldsize,f->clusiz)); + a->usiz = f->size & 0xffff; + MARKF; + if (f->size >> 16) { /* large file */ + a->urts[1] = f->size >> 16; + if ((oldsize >> 16) == 0) { /* it was small */ + if (a->urts[0]) { + printf ("Warning - RTS name cleared for large file "); + printcurname (f); + printf ("\n"); + a->urts[0] = 0; + } + readlk (f->nlink); + n = use(ufdne,k); + if (n->uprot & up_run) { + n->uprot &= ~up_run; + MARKF; + printf ("Warning - runnable protection bit cleared for large file "); + printcurname (f); + printf ("\n"); + } + } + } + } + return (totalbytes); +} + +/* return TRUE if the filename has an extension that suggests it's a text + * file, and FALSE otherwise. + */ + +const char textlist[][4] = + { "txt", "lst", "map", "sid", "log", "lis", + "rno", "doc", "mem", "bas", "b2s", "mac", + "for", "ftn", "fth", "cbl", "dbl", "com", + "cmd", "bat", "tec", "ctl", "odl", "ps ", + "c ", "h ", "ps", "c", "h", "src", + "alg", "" }; + +int textfile (char *name) +{ + char *p; + int i; + + p = strchr (name, '.'); + if (p == NULL) return (FALSE); /* no extension */ + p++; /* skip past the dot */ + for (i = 0; textlist[i][0] != '\0'; i++) + if (strcmp (textlist[i], p) == 0) return (TRUE); + return (FALSE); +} diff --git a/extracters/rstsflx/fileio.h b/extracters/rstsflx/fileio.h new file mode 100644 index 0000000..d26a0fe --- /dev/null +++ b/extracters/rstsflx/fileio.h @@ -0,0 +1,25 @@ +extern long seqio(firqb * f , long iolen , iohandler io , void * buffer); + /* Prototype include a typedef name. + It should be moved after the typedef declaration */ +extern void openfile(firqb * f); + /* Prototype include a typedef name. + It should be moved after the typedef declaration */ +extern void initrandom(firqb * f); + /* Prototype include a typedef name. + It should be moved after the typedef declaration */ +extern void fileseek(firqb * f , long vbn); + /* Prototype include a typedef name. + It should be moved after the typedef declaration */ +extern long getfile(FILE * to , firqb * f , int binary); + /* Prototype include a typedef name. + It should be moved after the typedef declaration */ +extern long extfile(firqb * f , long blocks); + /* Prototype include a typedef name. + It should be moved after the typedef declaration */ +extern long writefile(firqb * f , long count); + /* Prototype include a typedef name. + It should be moved after the typedef declaration */ +extern long putfile(FILE * from , firqb * f , int binary); + /* Prototype include a typedef name. + It should be moved after the typedef declaration */ +extern int textfile(char * name); diff --git a/extracters/rstsflx/filename.c b/extracters/rstsflx/filename.c new file mode 100644 index 0000000..64e5245 --- /dev/null +++ b/extracters/rstsflx/filename.c @@ -0,0 +1,309 @@ +/* subroutines to handle rsts file name conversion and file spec parse */ + +#include +#include +#include +#include +#include + +#include "flx.h" +#include "filename.h" +#include "fldef.h" + +#define isr50(c) (isalnum (c) || (c) == ' ' || (c) == '?' || (c) == '*') + +const char *parsename (const char *p, firqb *out) /* parse the name part of a spec */ +{ + int n; + + for (n = 0; n < 6; n++) out->name[n] = ' '; + out->name[6] = '\0'; /* put in terminator */ + if (isr50(*p)) { /* name present */ + n = 0; + while (isr50(*p)) { + if (*p == ' ') { /* skip blanks */ + p++; + continue; + } + out->flags |= f_name; + if (*p == '*') { + if (n < 6) { + out->name[n++] = '?'; + out->flags |= f_namw; + } else p++; + } else { + if (n < 6) out->name[n++] = tolower (*p); + if (*p++ == '?') out->flags |= f_namw; + } + } + } + return (p); +} + +const char *parsenameext (const char *p, firqb *out) /* parse the name.ext part of a spec */ +{ + int n; + + for (n = 0; n < NAMELEN - 1; n++) out->name[n] = ' '; + p = parsename (p, out); /* parse the name part */ + out->name[6] = '.'; + out->name[NAMELEN - 1] = '\0'; /* put in terminator */ + if (*p == '.') { /* extension present */ + p++; + out->flags |= f_ext; + if (isr50(*p)) { + n = 0; + while (isr50(*p)) { + if (*p == ' ') { /* skip blanks */ + p++; + continue; + } + if (*p == '*') { + if (n < 3) { + out->name[7 + n++] = '?'; + out->flags |= f_extw; + } else p++; + } else { + if (n < 3) out->name[7 + n++] = tolower (*p); + if (*p++ == '?') out->flags |= f_extw; + } + } + } + } + return (p); +} + +int parse (const char *p, firqb *out) /* returns FALSE if error, TRUE if ok */ +{ + char *pp; + + out->proj = 0; + out->prog = 0; + out->flags = 0; + if (*p == '[' || *p == '(' || *p == '/') { /* PPN first */ + p++; + out->flags |= f_ppn; /* flag PPN present */ + if (*p == '*') { /* wild proj */ + p++; + out->proj = 255; + out->flags |= f_ppnw; + } else { + out->proj = strtoul (p, &pp, 10); + if (pp == p || out->proj > 254) return (FALSE); + p = pp; + } + if (*p != ',' && *p != '/') return (FALSE); + p++; + if (*p == '*') { /* wild prog */ + p++; + out->prog = 255; + out->flags |= f_ppnw; + } else { + out->prog = strtoul (p, &pp, 10); + if (pp == p || out->prog > 254) return (FALSE); + p = pp; + } + if (out->proj == 0 && out->prog == 0) return (FALSE); + if (*p != ']' && *p != ')' && + *p != '/' && *p != '\0') return (FALSE); + if (*p != '\0') p++; + } else switch (*p) { /* see if special PPN char */ + case '$': + out->proj = 1; /* supply [1,2] */ + out->prog = 2; + out->flags |= f_ppn; /* indicate PPN present */ + p++; /* skip that char */ + break; + case '!': + out->proj = 1; /* supply [1,3] */ + out->prog = 3; + out->flags |= f_ppn; /* indicate PPN present */ + p++; /* skip that char */ + break; + case '%': + out->proj = 1; /* supply [1,4] */ + out->prog = 4; + out->flags |= f_ppn; /* indicate PPN present */ + p++; /* skip that char */ + break; + case '&': + out->proj = 1; /* supply [1,5] */ + out->prog = 5; + out->flags |= f_ppn; /* indicate PPN present */ + p++; /* skip that char */ + break; + + default: /* no PPN supplied */ + out->proj = 1; /* supply default of [1,2] */ + out->prog = 2; /* don't set f_ppn flag */ + } + p = parsenameext (p, out); + if (*p == '<') { /* protection code present */ + p++; + out->flags |= f_prot; + out->newprot = strtoul (p, &pp, 10); + if (pp == p) return (FALSE); + p = pp; + if (*p++ != '>') return (FALSE); + } + return (*p == '\0'); /* success if all was parsed */ +} + +static const char r50table[] = " abcdefghijklmnopqrstuvwxyz$.?0123456789:"; + +char *r50toascii (word16 r50, char *string, int space) +{ + int t, c, pos; + + pos = 03100; + for (t = 0; t<3; t++) { + c = r50 / pos; + if (c || space) *string++ = r50table[c]; + r50 %= pos; + pos /= 050; + } + *string = '\0'; /* put in string terminator */ + return (string); +} + +char *r50toascii2 (word16 r50[], char *string, int space) +{ + string = r50toascii (r50[0], string, space); + return (r50toascii (r50[1], string, space)); +} + +void r50filename (word16 r50[], char *name, int space) +{ + name = r50toascii2 (r50, name, space); + *name++ = '.'; + name = r50toascii (r50[2], name, space); +} + +void printfqbppn (const firqb *f) +{ + if (f->proj == 255) printf ("[*,"); + else printf ("[%d,", f->proj); + if (f->prog == 255) printf ("*]"); + else printf ("%d]", f->prog); +} + +void printfqbname (const firqb *f) +{ + int n; + + printfqbppn (f); + for (n = 0; n < NAMELEN - 1; n++) + if (f->name[n] != ' ') putchar (f->name[n]); +} + +void printcurname (const firqb *f) +{ + if (f->stat & us_ufd) + { + if (f->cproj == 255) + printf ("[*,*]"); + else if (f->cprog == 255) + printf ("[%d,*]", f->cproj); + else printf ("[%d,%d]", f->cproj, f->cprog); + } + else printf ("[%d,%d]%s", f->cproj, f->cprog, f->cname); +} + +/* merge a native (unix or dos) input filespec or RSTS name.ext with a + * (possibly wild) rsts output file spec to produce the specific output + * filename as a 3-word rad50 value. If the third argument is TRUE, then + * the last directory element in the input filename path must be numeric, + * and is used to set the current PPN fields in the output FIRQB. + */ +void mergename (char *iname, firqb *oname, int tree) +{ + int n, spflag; + firqb inf; + char c; + char *in1, *in2; + char tname[FILENAME_MAX]; + int ppn; + + if ((in1 = strrchr (iname, '/')) != NULL) in1++; + else in1 = iname; + if ((in2 = strrchr (in1, '\\')) != NULL) in1 = in2 + 1; + inf.flags = 0; /* clear parse flags */ + if (*(parsenameext (in1, &inf)) != '\0' /* see if we can parse that */ + || (inf.flags & F_WILD)) /* it should not have * or ? */ + memcpy (inf.name, "xxxxxx.xxx", NAMELEN); /* use xxx if bad name */ + oname->cname[6] = '.'; /* make sure . is in */ + spflag = FALSE; /* no spaces yet */ + for (n = 0; n < NAMELEN - 1; n++) { + if (n == 6) { + spflag = FALSE; /* no spaces yet in ext */ + continue; /* skip the '.' separator */ + } + c = oname->name[n]; /* start with output spec */ + if (c == '?' && !spflag) + c = inf.name[n]; /* use input if output wild */ + if (c == ' ') spflag = TRUE; /* stop if we find a space */ + if (spflag) c = ' '; /* force spaces after space */ + oname->cname[n] = c; /* store result */ + } + oname->cname[NAMELEN - 1] = '\0'; /* ensure terminator */ + if (tree) { + n = in1 - iname; /* get offset to name part */ + if (n) n--; /* now to the / */ + else { + oname->cproj = oname->cprog = 0; /* can't set PPN from iname */ + return; + } + strcpy (tname, iname); /* copy the name */ + tname[n] = '\0'; /* chop off directory part */ + if ((in1 = strrchr (tname, '/')) != NULL) in1++; + else in1 = tname; + if ((in2 = strrchr (in1, '\\')) != NULL) in1 = in2 + 1; + ppn = strtoul (in1, &in2, 10); /* convert to decimal */ + if (*in2 != '\0') ppn = 0; /* check for error */ + if (oname->proj == 255) { + if (strlen (in1) < 4) ppn = 0; + oname->cproj = ppn / 1000; /* proj = first digits */ + } else oname->cproj = oname->proj; + if (oname->prog == 255) + oname->cprog = ppn % 1000; + else oname->cprog = oname->prog; + if (oname->cproj > 254 || oname->cprog > 254) + oname->cproj = oname->cprog = 0; + } + return; +} + +/* routines to convert ascii names to rad50. These assume that the name + * is valid rad50, i.e., letters and digits only. Special case: for the + * parsing of RTS names, '.' is also accepted as a rad50 character. + * Any non-rad50 character is treated as space, i.e., rad50 0. + */ + +word cvtr50 (const char *in) +{ + int mul, r50, n; + + for (r50 = 0, mul = 03100, n = 0; n < 3; in++, mul /= 050, n++) { + if (isdigit (*in)) r50 += (*in - '0' + 036) * mul; + else if (isalpha (*in)) r50 += (tolower (*in) - 'a' + 001) * mul; + else if (*in == '.') r50 += 034 * mul; + } + return (r50); +} + +/* convert 6-character name */ + +void cvtnametor50 (const char *in, word16 *out) +{ + out[0] = cvtr50 (in); + out[1] = cvtr50 (in + 3); +} + +/* convert name.ext */ + +void cvtnameexttor50 (const char *in, word16 *out) +{ + cvtnametor50 (in, out); + out[2] = cvtr50 (in + 7); /* skip the "." */ +} + diff --git a/extracters/rstsflx/filename.h b/extracters/rstsflx/filename.h new file mode 100644 index 0000000..1c702f1 --- /dev/null +++ b/extracters/rstsflx/filename.h @@ -0,0 +1,39 @@ +extern const char * parsename(const char * p , firqb * out); + /* Prototype include a typedef name. + It should be moved after the typedef declaration */ +extern const char * parsenameext(const char * p , firqb * out); + /* Prototype include a typedef name. + It should be moved after the typedef declaration */ +extern int parse(const char * p , firqb * out); + /* Prototype include a typedef name. + It should be moved after the typedef declaration */ +extern char * r50toascii(word16 r50 , char * string , int space); + /* Prototype include a typedef name. + It should be moved after the typedef declaration */ +extern char * r50toascii2(word16 r50[] , char * string , int space); + /* Prototype include a typedef name. + It should be moved after the typedef declaration */ +extern void r50filename(word16 r50[] , char * name , int space); + /* Prototype include a typedef name. + It should be moved after the typedef declaration */ +extern void printfqbppn(const firqb * f); + /* Prototype include a typedef name. + It should be moved after the typedef declaration */ +extern void printfqbname(const firqb * f); + /* Prototype include a typedef name. + It should be moved after the typedef declaration */ +extern void printcurname(const firqb * f); + /* Prototype include a typedef name. + It should be moved after the typedef declaration */ +extern void mergename(char * iname , firqb * oname , int tree); + /* Prototype include a typedef name. + It should be moved after the typedef declaration */ +extern word cvtr50(const char * in); + /* Prototype include a typedef name. + It should be moved after the typedef declaration */ +extern void cvtnametor50(const char * in , word16 * out); + /* Prototype include a typedef name. + It should be moved after the typedef declaration */ +extern void cvtnameexttor50(const char * in , word16 * out); + /* Prototype include a typedef name. + It should be moved after the typedef declaration */ diff --git a/extracters/rstsflx/fip.c b/extracters/rstsflx/fip.c new file mode 100644 index 0000000..2462120 --- /dev/null +++ b/extracters/rstsflx/fip.c @@ -0,0 +1,1544 @@ +/* rsts file processing subroutines */ + +#include +#include +#include + +#include "flx.h" +#include "fldef.h" +#include "fip.h" +#include "diskio.h" +#include "rtime.h" +#include "filename.h" + +byte fibuf[BLKSIZE]; /* buffer for directories */ +byte *sattbufp; /* pointer to SATT buffer */ +int sattsize; /* size of SATT.SYS file in bytes */ +long pcns; /* number of pack clusters on this disk */ +long sattlbn; /* start LBN of SATT */ +long satptr; /* current allocation pointer (PCN) */ +int womsat; /* TRUE if SATT needs to be written back */ +long fiblk; /* current block in FIBUF */ +int fiblkw; /* TRUE if FIBUF needs to be written back */ + +void fbwrite (void) /* write current block from fibuf */ +{ + rwrite (fiblk, BLKSIZE, fibuf); + fiblkw = FALSE; +} + +void checkwrite (void) +{ + if (fiblkw) fbwrite (); +} + +void fbread (long block) /* read block into fibuf if needed */ +{ + if (fiblk != block) + { + checkwrite (); + rread (block, BLKSIZE, fibuf); + fiblk = block; + } +} + +void readdcn (long dcn) +{ + fbread (dcntolbn(dcn)); +} + +long i,k; /* current directory entry pointers */ + +/* ulk unpacks a rsts directory link, returning the LBN in i and + * the byte offset in k. + * it returns 0 if ok, BADLINK if not. bad" means block offset out + * of range (should be less than cluster size), cluster number 7, + * or byte offset 760 octal (belongs to fdcm). + */ + +int ulk (word link) +{ + int clu, blk; + + k = (link & ul_eno); /* k = byte offset to entry */ + clu = (link & ul_clo) >> sl_clo; /* cluster number */ + blk = (link & ul_blo) >> sl_blo; /* block in cluster */ + if (sw.debug != NULL) + printf ("ulk(%o), k=%lo, clu=%d, blk=%d, clumap=%d\n", + link, k, clu, blk, clumap->uent[clu]); + if (blk >= clumap->uclus || + clu > 6 || + k == 0760 || + clumap->uent[clu] == 0) + return (BADLINK); + i = blk + dcntolbn(clumap->uent[clu]); /* LBN of entry */ + return (0); /* ok */ +} + +/* readlk reads the directory block pointed to by the supplied link. + * i and k are set as for ulk. If the link is null, this routine + * returns FALSE; otherwise it returns TRUE. readlk2 works similarly, + * but it unconditionally reads what the link points to; thus it can be + * used to read the label blockette of a directory (and readlk cannot!!!) + * readlktbl is similar to readlk, except that it is meant to be called + * when the block currently in fibuf is the GFD name entry link table -- + * which doesn't have a cluster map. curgfd must be set for it to work. + */ + +void readlk2 (word link) +{ + if (ulk (link)) + rabort(CORRUPT); /* unpack the link */ + fbread (i); /* read the directory block */ +} + +int readlk (word link) +{ + if (NULLINK(link)) + return (FALSE); /* reject null link */ + readlk2 (link); /* otherwise read it */ + return (TRUE); +} + +int readlktbl (word link) +{ + if (NULLINK(link)) + return (FALSE); /* null link, exit now */ + if (link & ul_clo) + fbread (curgfd); /* get gfd block with fdcm */ + else + fbread (curgfd + ((link & ul_blo) >> sl_blo)); + return (readlk (link)); /* now do the actual read */ +} + +/* utility routines for getclu */ + +/* both of these scan the satt from "start" through "last", looking + * to allocate a chunk of "clucount" clusters, with clustersize + * "clusiz" (i.e., aligned on "clusiz" boundary) -- both of the latter + * being expressed as a count of pack clusters. + * scanbytes works for clusiz >= 8, where the scan is for whole bytes of + * zero. scanbits works for smaller clusiz values, and looks for fields + * of zero bits. In both cases, if a spot is found, it is allocated, + * satptr is set to the next cluster after the allocated area, and the + * start DCN returned; zero means failure (and SATT and satptr are + * unchanged). + */ + +long scanbytes (long start, long last, int clusiz, long clucount) +{ + long clusizbyt, clu, cluoff, clucountbyt, found; + byte *s; + + clusizbyt = clusiz / 8; /* byte alignment needed */ + clucountbyt = clucount / 8; /* allocation size in bytes */ + s = sattbufp + (start / 8); /* byte pointer to start of scan */ + for (clu = start; clu <= last; clu += clusiz, s+= clusizbyt) + { + if (*s != 0) + continue; /* if not free, keep scanning */ + found = TRUE; /* found something... */ + for (cluoff = 1; cluoff < clucountbyt; cluoff++) + if (*(s + cluoff) != 0) + { + cluoff = DOWN(cluoff,clusizbyt); + s += cluoff; + clu += cluoff * 8; + found = FALSE; /* never mind... */ + break; + } + if (!found) + continue; /* keep going if no luck */ + for (cluoff = 0; cluoff < clucountbyt; cluoff++) *s++ = 0xff; + satptr = clu + clucount; /* update satptr */ + MARKS; /* SATT is dirty */ + return (pcntodcn(clu)); + } + return (0); /* nothing found */ +} + +long scanbits (long start, long last, int clusiz, long clucount) +{ + long mask, mask1, mask2, cluoff, clu, found; + byte *s, *s2; + + clucount /= clusiz; /* make it count of file clusters */ + mask1 = (1 << clusiz) - 1; /* mask to match on */ + s = sattbufp + start / 8; /* byte pointer to start of scan */ + mask = mask1 << (start % 8); /* form starting bit field */ + for (clu = start; clu <= last; clu += clusiz) + { + if ((*s & mask) != 0) /* not all free, keep looking... */ + { + if (mask < 0x80) + mask <<= clusiz; + else + { + mask = mask1; + s++; + } + continue; + } + found = TRUE; /* found something... */ + mask2 = mask; /* now look for contiguous piece */ + s2 = s; + for (cluoff = 0; cluoff < clucount; cluoff++) + { + if ((*s2 & mask2) != 0) /* not all free, keep looking... */ + { + clu += cluoff; + if (mask2 < 0x80) + mask2 <<= clusiz; + else + { + mask2 = mask1; + s2++; + } + s = s2; + mask = mask2; /* continue just past here */ + found = FALSE; /* never mind... */ + break; + } + if (mask2 < 0x80) + mask2 <<= clusiz; + else + { + mask2 = mask1; + s2++; + } + } + if (!found) + continue; /* keep going if no luck */ + for (cluoff = 0; cluoff < clucount; cluoff++) + { + *s |= mask; + if (mask < 0x80) + mask <<= clusiz; + else + { + mask = mask1; + s++; + } + } + satptr = clu + clucount; /* update satptr */ + MARKS; /* SATT is dirty */ + return (pcntodcn(clu)); + } + return (0); /* nothing found */ +} + +/* getclu allocates clusters of the specified size, for a file of specified + * total size. before calling this routine, the pack should be mounted + * read/write to ensure a rebuild is forced if things abort after this point. + * If there is no room, zero is returned. Otherwise the starting DCN + * is returned. + * A single allocation is done, so the "size" argument should be equal to + * the clustersize unless a contiguous allocation is being done. + */ + +int pcs; /* pack clustersize */ + +long getclu (int clusiz, long size) +{ + long start, alloc, clucount; + + if (sw.debug != NULL) + printf ("getclu(%d,%ld)\n", clusiz, size); + if (sattsize == 0) + rabort(INTERNAL); + clusiz /= pcs; /* fcs as count of clusters */ + clucount = size / pcs; /* ditto for total size wanted */ + if (clusiz <= 0) + rabort(INTERNAL); + if (clucount <= 0) + rabort(INTERNAL); + start = UP(satptr,clusiz); /* align start of scan */ + if (clusiz < 8) /* scanning bitwise */ + { + alloc = scanbits (start, pcns - clucount, clusiz, clucount); + if (alloc) + return (alloc); /* found it in rest of satt */ + return (scanbits (0, start - clusiz, clusiz, clucount)); + } + else /* scanning whole bytes */ + { + alloc = scanbytes (start, pcns - clucount, clusiz, clucount); + if (alloc) + return (alloc); /* found it in rest of satt */ + return (scanbytes (0, start - clusiz, clusiz, clucount)); + } +} + +/* retclu returns a single cluster. "pos" is the DCN of the cluster, + * (i.e., as found in retrieval entries); "clusiz" is the file clustersize. + */ + +void retclu (long pos, int clusiz) +{ + long m, n; + byte *s; + + if (sw.debug != NULL) + printf ("retclu(%lo,%d)\n", pos, clusiz); + if (sattsize == 0) + rabort(INTERNAL); + pos = dcntopcn(pos); /* convert to pcn */ + clusiz /= pcs; /* fcs as count of clusters */ + if (clusiz <= 0) + rabort(INTERNAL); + s = sattbufp + pos / 8; /* byte pointer to start of cluster */ + if (clusiz < 8) /* scanning bitwise */ + { + m = (1 << clusiz) - 1; /* mask to match on */ + m <<= (pos % 8); /* form starting bit field */ + *s &= ~m; /* free this cluster */ + } + else /* scanning whole bytes */ + { + clusiz /= 8; /* change to count of bytes to free */ + for (n = 0; n < clusiz; n++) *s++ = 0; + } + MARKS; /* mark SATT dirty */ +} + +int pflags; /* pack flags */ +int plevel; /* pack structure revision level */ +long mfddcn; /* DCN of start of MFD */ +long mfdlbn; /* LBN of start of MFD */ +char pname[7]; /* pack ID in ascii */ + +void readlabel (void) +{ + packlabel *p; + + readdcn (1); /* get pack label */ + p = use(packlabel,0); + pcs = p->ppcs; /* get PCS */ + pflags = p->pstat; /* get pack flags */ + if (pflags & uc_new) + { + plevel = p->plvl; /* get RDS level */ + mfddcn = p->mdcn; /* get MFD pointer */ + } + else + { + plevel = 0; /* set to 0 if old pack */ + mfddcn = 1; /* MFD is at 1 for old format */ + } + mfdlbn = dcntolbn(mfddcn); /* for convenience, LBN also */ + r50toascii2 (p->pckid, pname, FALSE); /* translate pack ID */ +} + +long curgfd; /* LBN of start of current GFD */ +long curqblbn; /* LBN where current ppn quota block lives */ +word curqb; /* and link pointing to it */ +int entptr; /* current directory entry allocation pointer */ +word nextlink; /* link to next file */ +word prevlink; /* link to prececessor of file */ +word nextppnlink; /* link to next PPN for RDS 0 */ +word prevppnlink; /* link to prececessor of PPN for RDS 0*/ + +void setppn (firqb *f, int proj, int prog, word ppnent, int which) +{ + f->cproj = proj; + f->cprog = prog; + curqb = 0; /* haven't found quota block yet */ + if (which == gfddcntbl) /* looking for UFD */ + { + ppnent = dcntolbn(ppnent); + fbread (ppnent); /* read it */ + prevlink = 0; + nextlink = use(ufdlabel,0)->ulnk; + entptr = sizeof (ufdlabel); + } + else readlktbl (ppnent); +} + +word nextppn (firqb *f, int which) /* find next ppn */ +{ + int firstproj, firstprog, lastproj, lastprog; + int j, n; + word ppnent; + word curlink; + gfdne *d; + + nextlink = 0; /* assume nothing found */ + if (plevel == RDS0) /* if old pack */ + { + readlktbl (nextppnlink); /* read next MFD NE */ + while (!NULLINK(nextppnlink)) + { + readlk (nextppnlink); /* read it */ + curlink = nextppnlink; + d = use(gfdne,k); + nextppnlink = d->ulnk; /* point to next one */ + if ((d->ustat & (us_del | us_ufd)) == us_ufd + && (f->proj == 255 || f->proj == (d->unam[0] >> 8)) + && (f->prog == 255 || f->prog == (d->unam[0] & 0xff))) + { + f->cproj = d->unam[0] >> 8; + f->cprog = d->unam[0] & 0xff; + if (which == gfddcntbl) /* looking for UFD */ + { + ppnent = dcntolbn(d->uar); + if (ppnent == 0) + /* PPN without UFD, skip */ + continue; + fbread (ppnent); /* read it */ + prevlink = 0; + nextlink = use(ufdlabel,0)->ulnk; + entptr = sizeof (ufdlabel); + } + else ppnent = curlink; + return (ppnent); + } + prevppnlink = curlink; + } + return (0); + } + firstproj = f->cproj; + if (f->proj == 255) lastproj = 254; + else lastproj = f->proj; + if (f->prog == 255) + { + firstprog = 0; + lastprog = 254; + } + else firstprog = lastprog = f->prog; + n = f->cprog + 1; /* next prog number to try */ + for (j = firstproj; j <= lastproj; j++) + { + fbread (mfdlbn + gfddcntbl); + if ((curgfd = dcntolbn(fibufw[j])) == 0) + continue; + fbread (curgfd + which); + for ( ; n <= lastprog; n++) + { + if ((ppnent = fibufw[n]) == 0) + continue; + setppn (f, j, n, ppnent, which); + return (ppnent); + } + n = firstprog; /* next project, start at firstprog */ + } + return (0); +} + +word initfilescan (firqb *f, int which) /* setup file scan to the beginning */ +{ + int firstproj, firstprog, lastproj, lastprog; + int j, n; + word ppnent; + + nextlink = prevlink = 0; /* assume nothing found */ + if (plevel == RDS0) /* if old pack */ + { + prevppnlink = 0; + curgfd = mfdlbn; /* pretent MFD is also GFD */ + fbread (mfdlbn); /* read start of MFD */ + nextppnlink = use(packlabel,0)->ulnk; + return (nextppn (f, which)); /* and look for first match */ + } + if ((f->flags & f_name) == 0) + { + f->cproj = f->proj; + f->cprog = f->prog; + if (f->proj == 255) + { + fbread (mfdlbn); + return (mfddcn); + } + if (f->prog == 255) + { + fbread (mfdlbn + gfddcntbl); + if ((ppnent = fibufw[f->proj]) == 0) + return (0); + curgfd = dcntolbn (ppnent); + fbread (curgfd); + return (ppnent); + } + firstproj = lastproj = f->proj; + firstprog = lastprog = f->prog; + } + else + { + if (f->proj == 255) + { + firstproj = 0; + lastproj = 254; + } + else firstproj = lastproj = f->proj; + if (f->prog == 255) + { + firstprog = 0; + lastprog = 254; + } + else firstprog = lastprog = f->prog; + } + for (j = firstproj; j <= lastproj; j++) + { + fbread (mfdlbn + gfddcntbl); + if ((curgfd = dcntolbn(fibufw[j])) == 0) + continue; + fbread (curgfd + which); + for (n = firstprog; n <= lastprog; n++) + { + if (n == 0 && j == 0) + continue; + if ((ppnent = fibufw[n]) == 0) + continue; + setppn (f, j, n, ppnent, which); + return (ppnent); + } + } + return (0); +} + +int wmatch (const char *wn, const char *n) /* wildcard match */ +{ + while (*wn != '\0') + { + if (*wn != *n && *wn != '?') + return (FALSE); + wn++; + n++; + } + return (TRUE); +} + +/* nextfileindir looks for a file in the current directory. If found, it + * updates the file informationin the supplied firqb (name, links, status, + * protection code, size, clustersize). + * A return of TRUE means match, FALSE means nothing found. + * Special case: if the filename is null, the indicated director is opened. + * In that case, "prevlink" is set non-zero to indicate that this is the + * only "match" on this directory. "Indicated directory" can be the GFD + * or MFD if the proj and prog were wild. + */ + +int nextfileindir (firqb *f) +{ + ufdne *n; + ufdae *a; + ufdrms1 *r; + int ent; + + if ((f->flags & f_name) == 0) /* null name, open UFD */ + { + if (prevlink) + return (FALSE); + prevlink++; /* return no match next time */ + if (f->prog == 255) + { + if (f->proj == 255) + fbread (mfdlbn); + else + fbread (curgfd); + } + f->stat = us_ufd | us_nok; + f->prot = 63; + f->clusiz = clumap->uclus; + f->size = 0; + for (ent = 0; ent < 7; ent++) + if (clumap->uent[ent]) + f->size += clumap->uclus; + f->rmslink = 0; + f->recfmt = rf_stm; /* default to stream */ + f->eofblk = f->size; + f->eofbyte = 0; + sprintf (f->cname, "%03d%03d.dir", f->cproj, f->cprog); + return (TRUE); + } + while (readlk (nextlink)) /* read next entry, if any */ + { + n = use(ufdne,k); + f->nlink = nextlink; /* save this link */ + nextlink = n->ulnk; /* link to next entry */ + if ((n->ustat & (us_ufd | us_del)) == 0) + { + r50filename (n->unam, f->cname, TRUE); + if (wmatch (f->name, f->cname)) + { + f->stat = n->ustat; + f->prot = n->uprot; + f->rlink = n->uar; + f->alink = n->uaa; + if (!readlk (f->alink)) + rabort(CORRUPT); + a = use(ufdae,k); + f->size = a->usiz; + f->clusiz = a->uclus; + f->rmslink = a->ulnk; + if (a->urts[0] == 0) + f->size += a->urts[1] << 16; + if (NULLINK(f->rmslink)) + { + f->recfmt = rf_stm; /* default to stream */ + f->eofblk = f->size; + f->eofbyte = 0; + } + else + { + readlk (f->rmslink); + r = use(ufdrms1,k); + f->recfmt = r->fa_typ; + f->recsiz = r->fa_rsz; + f->eofblk = ((long)(r->fa_eof[0]) << 16) + r->fa_eof[1]; + f->eofbyte = r->fa_eofb; + if (f->eofbyte == BLKSIZE) + { + f->eofbyte = 0; + f->eofblk++; + } + if ((r->fa_typ & fa_rfm) == rf_vfc) + { + if (NULLINK(r->ulnk)) + f->rechdrsiz = 0; + else + { + readlk(r->ulnk); + f->rechdrsiz = use(ufdrms2,k)->fa_hsz; + } + } + } + return (TRUE); + } + } + prevlink = f->nlink; /* save link to predecessor */ + } + return (FALSE); /* not found */ +} + +/* nextfile looks for the next matching filespec, going across directories + * as needed. If a match is found, it returns TRUE and loads the supplied + * firqb with information about the file. Otherwise, FALSE is returned. + * Special case: if the filename is null, the current UFD is opened. + */ + +int nextfile (firqb *f) /* find next match for this filespec */ +{ + for (;;) + { + if (nextfileindir (f)) + { + return (TRUE); + } + if (nextppn (f, gfddcntbl) == 0) + return (FALSE); + } +} + +int findfile (firqb *f, const char *name) /* find a single file by name */ +{ + parse (name, f); + initfilescan (f, gfddcntbl); + return (nextfile (f)); +} + +int findqb (const firqb *f) /* find quota block for current ppn */ +{ + word link; + ua_quo *a; + + if (plevel < RDS11) + rabort(INTERNAL); + if (curgfd == 0) + rabort(INTERNAL); + fbread (curgfd + gfdatrtbl); /* read attribute link table */ + link = fibufw[f->cprog]; /* fetch appropriate link */ + if (link & ul_clo) fbread (curgfd); /* get gfd block with fdcm */ + else fbread (curgfd + ((link & ul_blo) >> sl_blo)); + if (!readlk (link)) rabort(INTERNAL); /* read dir NE */ + link = use(gfdne,k)->ulnk; /* get link to first attribute */ + while (link) + { + readlk (link); /* read an attribute entry */ + a = use(ua_quo,k); + if (a->uatyp == aa_quo) return (link); /* found it */ + link = a->ulnk; /* follow the link */ + } + rabort(CORRUPT); /* bogus -- no quota block */ + return (0); /* to make the compiler happy */ +} + +void updqb (const firqb *f, long delta) /* adjust quota by delta blocks */ +{ + long quo, savefiblk; + ua_quo *q; + + if (sw.debug != NULL) + printf ("updqb(,%ld), RDS %d.%d\n", + delta, plevel >> 8, plevel & 0xff); + if (plevel < RDS12) + return; /* NOP if not RDS 1.2 */ + if (f->cproj == 0 && f->cprog == 1) + return; /* NOP for [0,1] */ + savefiblk = fiblk; /* remember current block */ + if (curqb == 0) /* if we haven't been here yet */ + { + curqb = findqb (f); /* find it */ + curqblbn = fiblk; /* and remember LBN also */ + } + else + { + fbread (curqblbn); /* read block where it lives */ + ulk (curqb); /* and set up "k" */ + } + q = use(ua_quo,k); /* point to it */ + quo = (q->aq_crm << 16) + q->aq_crl; + quo += delta; /* adjust the usage */ + q->aq_crl = quo & 0xffff; /* update low order */ + q->aq_crm = quo >> 16; /* and high order */ + MARKF; /* mark FIBUF for write */ + fbread (savefiblk); /* restore caller's FIBUF content */ +} + +/* upddlw updates the dlw/dla field; it is called when the file has + * been changed. note that we don't implement date of last access + * recording; this avoids having to write to disks that would otherwise + * only be read. + */ + +void upddlw (const firqb *f) /* update date of last write */ +{ + if (sw.debug != NULL) + printf ("upddlw( )\n"); + if (f->stat & us_ufd) + return; /* nop on directories! */ + if (!readlk (f->alink)) + rabort(INTERNAL); + use(ufdae,k)->udla = curdate (); + MARKF; +} + +/* extdir extends the current directory by one cluster, if possible. + * it returns the DCN of the cluster allocated, if successful, or 0 + * if allocation failed. If it succeeded, all directory clustermaps + * have been updated, and the new cluster has been otherwise set to zero. + * This routine works for any kind of directory, MFD and GFD included. + * On completion, some directory block is in FIBUF. If successful, + * it is the FIRST block of the directory (NOT any of the allocated + * cluster!). + * + * extdir2 either creates the first cluster of a directory or extends + * a directory by one cluster. It is called from extdir (and also + * directly in processing the "init" command). It is passed the clustersize, + * clustermap entry offset, clustermap flags, and directory label data + * to be used. (If a cluster other than first is being allocated, only + * entry offset, flags, and clustersize arguments are used.) The flags + * argument is used to control whether an mfd/gfd vs. a ufd is being + * extended. Since this affects which blocks have to be updated, it + * is important to pass the correct value. + */ + +int extdir2 (int newcm, int clusiz, byte flags, const ufdlabel *newl) +{ + long clu, lbn; /* new cluster and its lbn */ + int cm, off; /* clustermap entry and offset */ + int realclu; /* clustersize for getclu */ + ufdlabel *u; + + if (sw.debug != NULL) + { + printf ("extdir2(%d,%d,%o)\n", newcm, clusiz, flags); + printf (" old map: %03o %03o %06o %06o %06o %06o %06o %06o %06o\n", + clumap->uclus, clumap->uflag, clumap->uent[0], + clumap->uent[1], clumap->uent[2], + clumap->uent[3], clumap->uent[4], + clumap->uent[5], clumap->uent[6]); + } + checkwrite (); /* make sure pending write is done */ + realclu = clusiz; + if (clusiz < pcs) + realclu = pcs; /* for big disks, if pcs > 16 */ + clu = getclu (realclu, realclu); /* get one cluster that size */ + if (clu == 0) + return (FALSE); /* sorry, nothing available */ + lbn = dcntolbn(clu); /* get corresponding start LBN */ + for (cm = 0; cm < newcm; cm++) /* update old clusters, if any */ + { + for (off = 0; off < clusiz; off++) + { + if (cm == 0) /* first cluster needs some checks */ + { + if (off == 0) + continue; /* do this last */ + if ((flags & fd_new) && off <= gfdatrtbl) + continue; /* skip tables */ + } + fbread (dcntolbn(clumap->uent[cm]) + off); + clumap->uent[newcm] = clu; + fbwrite (); /* write updated data */ + } + } + + if (newcm == 0) /* creating the first cluster */ + { + off = 1; /* Assume updating a UFD */ + if (flags & fd_new) + off = gfdatrtbl + 1; /* Adjust if MFD/GFD */ + memset (fibuf, 0, BLKSIZE); /* zero entire block */ + if (flags & fd_new) /* erase table blocks if MFD/GFD */ + { + rwrite (lbn + gfddcntbl, BLKSIZE, fibuf); + rwrite (lbn + gfdatrtbl, BLKSIZE, fibuf); + } + clumap->uclus = clusiz; /* set up fixed fields in cluster map */ + clumap->uflag = flags; /* flags too */ + clumap->uent[0] = clu; /* this is the only cluster */ + } + else + { + /* Special case: if we're creating the second cluster of a + * directory of cluster size 1, then the above code does + * nothing. So we need to read cluster 0 explicitly to get + * the old cluster map. + */ + if (newcm == 1 && clusiz == 1) + { + readdcn (clumap->uent[0]); + clumap->uent[newcm] = clu; + } + memset (fibuf, 0, BLKSIZE - sizeof (fdcm)); + off = 0; /* updating entire new cluster */ + } + for ( ; off < clusiz; off++) + rwrite (lbn + off, BLKSIZE, fibuf); + if (newcm == 0) /* initialize directory label */ + { + fiblk = lbn; /* we're building this block */ + u = use(ufdlabel,0); + memcpy (u, newl, sizeof (ufdlabel)); + } + else + { + fiblk = -1; /* nothing in fibuf */ + readdcn (clumap->uent[0]); /* read first block of dir */ + clumap->uent[newcm] = clu; /* update that last */ + } + fbwrite (); /* write updated data */ + if (sw.debug != NULL) + printf (" new map: %03o %03o %06o %06o %06o %06o %06o %06o %06o\n", + clumap->uclus, clumap->uflag, clumap->uent[0], + clumap->uent[1], clumap->uent[2], + clumap->uent[3], clumap->uent[4], + clumap->uent[5], clumap->uent[6]); + return (clu); /* it worked! return new DCN */ +} + +int extdir (void) /* extend current directory */ +{ + int clusiz; /* directory clustersize */ + int newcm; /* clustermap entry to update */ + + if (sw.debug != NULL) + printf ("extdir()\n"); + if (clumap->uent[6]) + return (0); /* already max length dir */ + for (newcm = 0; ; newcm++) if (clumap->uent[newcm] == 0) break; + clusiz = clumap->uclus; /* get dir clustersize */ + return (extdir2 (newcm, clusiz, clumap->uflag, NULL)); +} + +/* Check if the UFD has been allocated yet for a PPN; if not, allocate + * the first cluster. Returns 0 on failure, or start LBN of the UFD + * otherwise (including if the UFD already exists). + */ + +/* the 255,255 is overwritten with the PPN */ + +ufdlabel newulabel = { 0, 0177777, {0, 0, 0, 0}, {255, 255}, UFD }; + +int allocufd (word dirne, firqb *f) +{ + long savegfdlbn, savelbn; + word dirae; + gfdne *d; + gfdae *a; + + if (sw.debug != NULL) + printf ("allocufd (%d) for [%d,%d]\n", + dirne, f->cproj, f->cprog); + readlk (dirne); /* read the NE */ + d = use(gfdne,k); + if ((savelbn = dcntolbn(d->uar)) == 0) /* no UFD allocated yet */ + { + savegfdlbn = fiblk; /* remember where NE is */ + dirae = d->uaa; /* read AE for PPN */ + if (!readlk (dirae)) + rabort(CORRUPT); + a = use(gfdae,k); + newulabel.lppn[1] = f->cproj; /* fill in the label */ + newulabel.lppn[0] = f->cprog; + if (!extdir2 (0, a->uclus, 0, &newulabel)) + return (0); + savelbn = clumap->uent[0]; /* pick up DCN of UFD */ + fbread (savegfdlbn); /* re-read GFD */ + readlk (dirne); /* and set up for NE */ + use(gfdne,k)->uar = savelbn; /* set DCN of UFD */ + MARKF; + fbread (curgfd + gfddcntbl); /* read UFD pointer block */ + fibufw[f->cprog] = savelbn; /* set the new pointer (DCN) */ + MARKF; + savelbn = dcntolbn(savelbn); /* now make it an LBN */ + entptr = sizeof (ufdlabel); /* initialize the entry allocator */ + } + return (savelbn); +} +/* free entry search runs from entptr through end of directory. entptr + * initially points to start of dir. Anytime an entry is freed, entptr + * should be backed up to that entry if necessary. + * The value returned is the link to the entry, or 0 if none is available. + * The directory is extended if necessary, so 0 will be returned only if + * the disk is full or the directory already has 7 clusters, all full. + * In all cases, fibuf is left with a valid directory block in it. + * If the allocation succeeded, is it the block with the free entry, and + * k has the offset to it. If the allocation failed, it is some unspecified + * block of the directory. + * The entry is completely zeroed, and entptr points to it (not to the + * entry after it). So a second call to getent before any changes are + * made will find the same entry again! + */ + +int getent (void) /* get a free directory blockette */ +{ + int clu, blk, n; /* cluster and block being scanned */ + lword32 *l; + + if (sw.debug != NULL) + printf ("getent()\n"); + readlk2 (entptr); /* read starting point */ + clu = (entptr & ul_clo) >> sl_clo; /* convert entptr */ + blk = (entptr & ul_blo) >> sl_blo; + for (;;) + { + if (*use(lword,k) == 0) /* found an entry */ + { + entptr = k + (clu << sl_clo) + (blk << sl_blo); + readlk2 (entptr); /* read it */ + l = use (lword32, k); /* point to it */ + *l++ = 0; /* and clear it out */ + *l++ = 0; + *l++ = 0; + *l++ = 0; + MARKF; /* and mark it */ + return (entptr); /* this is what we found */ + } + if ((k += sizeof (ufdne)) == BLKSIZE - sizeof (fdcm)) + { + k = 0; + if (++blk < clumap->uclus) + { + if ((clumap->uflag & fd_new) + && clu == 0 && blk == gfddcntbl) + blk = gfdatrtbl + 1; + fbread (dcntolbn(clumap->uent[clu]) + blk); + } + else + { + blk = 0; + if (++clu > 6) return (0); /* we're FULL */ + if (clumap->uent[clu]) + readdcn (clumap->uent[clu]); + else + { + if ((n = extdir ()) != 0) + { + readdcn (n); + entptr = clu << sl_clo; + readlk2 (entptr); /* read it */ + return (entptr); + } + else + return (0); /* no room */ + } + } + } + } +} + +/* Release a directory entry. entptr is updated if necessary. + * The entire entry is cleared out. + */ + +void retent (word link) +{ + lword32 *l; + + if (sw.debug != NULL) printf ("retent(%o)\n", link); + if (!readlk (link)) rabort(INTERNAL); /* read the entry */ + l = use (lword32, k); /* point to it */ + *l++ = 0; /* and mark it as free */ + *l++ = 0; + *l++ = 0; + *l++ = 0; + MARKF; + if ((link & ul_clo) < (entptr & ul_clo) || + ((link & ul_clo) == (entptr & ul_clo) && link < entptr)) + entptr = link; /* move entptr back if needed */ +} + +/* Release the directory entries and allocated clusters for a file. + * This routine does not unlink it from the directory linked list; + * the caller has to do that. Nor does it make any protection checks. + */ + +void retfile (word nlink) +{ + word alink, rlink, rlink2, rmslink, clu, clusiz; + ufdne *n; + ufdae *a; + ufdrms1 *rms; + ufdre *r; + + if (sw.debug != NULL) + printf ("retfile(%o)\n", nlink); + if (!readlk (nlink)) + rabort(INTERNAL); /* read the NE */ + n = use(ufdne,k); + alink = n->uaa; + rlink = n->uar; /* save the links */ + retent (nlink); /* release the NE */ + if (!readlk (alink)) + rabort(CORRUPT); /* read the AE */ + a = use(ufdae,k); + clusiz = a->uclus; /* save fcs */ + rmslink = a->ulnk; + retent (alink); /* release the AE */ + if (!NULLINK(rmslink)) /* if RMS attributes present */ + { + readlk (rmslink); /* read the first */ + rms = use(ufdrms1,k); + if (!NULLINK(rms->ulnk)) + retent (rms->ulnk); + retent (rmslink); + } + while (!NULLINK(rlink)) /* release all RE's */ + { + readlk (rlink); /* read this one */ + r = use(ufdre,k); + rlink2 = r->ulnk; /* save link to next */ + for (clu = 0; clu < 7; clu++) + if (r->uent[clu]) + retclu (r->uent[clu], clusiz); + retent (rlink); /* release the RE */ + rlink = rlink2; + } +} + +void delfile (firqb *f) +{ + readlk2 (prevlink); + use(ufdne,k)->ulnk = nextlink; /* link previous to next */ + MARKF; + retfile (f->nlink); /* deallocate this file */ + updqb (f, -UP(f->size,f->clusiz)); /* adjust quota block */ + f->nlink = 0; /* zap link to former file */ +} + +/* Create a file given a filled-in firqb. The file is initially null, + * unless it is to be contiguous; in that case, it is pre-extended to + * the given size. The rts name to be assigned is also passed. The third + * and fourth arguments are used to supply RMS attribute block data if + * desired; if these are passed as NULL, no attribute blockettes are + * allocated for the file. + * prevlink must be set on entry (normally from an earlier call to nextfile). + * Return is TRUE if success, FALSE if failure. On failure, everything is + * released with the exception of any directory extension that may have been + * done. + * NOTE: this routine assumes that the file does NOT currently exist. + * The caller must verify this. + */ + +int crefile (firqb *f, const word16 *rtsname, + const ufdrms1 *rms1, const ufdrms2 *rms2) +{ + long dcn, startdcn, clu, clucount; + int dcnperfcs, reoff; + word re, prevre; + word rmslink2 = 0; + ufdne *n; + ufdae *a; + ufdrms1 *a1; + ufdrms2 *a2; + + if (sw.debug != NULL) + printf ("crefile()\n"); + if (pflags & uc_top) + { + prevlink = 0; /* link new file first */ + readlk2 (0); /* find current first */ + nextlink = use(ufdlabel,0)->ulnk; /* that will be next */ + } + else + nextlink = 0; /* otherwise no next */ + dcnperfcs = f->clusiz / dcs; /* # dev clu per file clu */ + if ((f->stat & us_nox) == 0) + f->size = 0; /* if not contiguous */ + f->rmslink = 0; + if (rms1 != NULL) /* if allocating attributes */ + { + if (rms2 != NULL) /* two of them! */ + { + if ((rmslink2 = getent ()) == 0) + return (FALSE); + readlk (rmslink2); + if (sw.debug != NULL) + printf ("crefile() rms2 at %o\n", rmslink2); + a2 = use(ufdrms2,k); + memcpy (a2, rms2, sizeof (ufdrms2)); + a2->ulnk = ul_use; /* mark in use */ + MARKF; + } + if ((f->rmslink = getent ()) == 0) + { + if (rmslink2) + retent (rmslink2); + return (FALSE); + } + readlk (f->rmslink); + if (sw.debug != NULL) + printf ("crefile() rms1 at %o\n", f->rmslink); + a1 = use(ufdrms1,k); + memcpy (a1, rms1, sizeof(ufdrms1)); + a1->ulnk = rmslink2 | ul_use; + MARKF; + } + if ((f->alink = getent ()) == 0) + { + if (f->rmslink) + retent (f->rmslink); + if (rmslink2) + retent (rmslink2); + return (FALSE); + } + readlk (f->alink); /* read new AE */ + if (sw.debug != NULL) + printf ("crefile() ae at %o\n", f->alink); + a = use(ufdae,k); + a->ulnk = f->rmslink | ul_use; /* mark in use */ + a->usiz = f->size & 0xffff; /* set low order size */ + a->udla = a->udc = curdate (); /* set dates */ + a->utc = curtime (); /* and creation time */ + a->uclus = f->clusiz; /* and clustersize */ + if (f->size >> 16) /* if large file */ + a->urts[1] = f->size >> 16; /* set high order size */ + else + { + a->urts[0] = rtsname[0]; /* set rts name */ + a->urts[1] = rtsname[1]; + } + MARKF; + if ((f->nlink = getent ()) == 0) /* try to get NE */ + { + if (f->rmslink) retent (f->rmslink); + if (rmslink2) retent (rmslink2); + retent (f->alink); /* no go, release AE */ + return (FALSE); + } + readlk (f->nlink); + if (sw.debug != NULL) + printf ("crefile() ne at %o\n", f->nlink); + n = use(ufdne,k); + cvtnameexttor50 (f->cname, n->unam); /* set file name.ext */ + n->uaa = f->alink; /* link AE to NE */ + n->ustat = f->stat; + n->uprot = f->newprot; /* set status and protection */ + MARKF; + f->rlink = 0; /* no RE's allocated yet */ + if (f->size) /* do contiguous extend */ + { + clucount = UP(f->size,f->clusiz); /* round size up to cluster */ + startdcn = getclu (f->clusiz, clucount); + clucount /= f->clusiz; /* now get cluster count */ + if (startdcn == 0) /* if it failed... */ + { + retfile (f->nlink); /* make file go away */ + return (FALSE); /* and exit */ + } + if (sw.debug != NULL) printf ("crefile() dcn %lo\n", startdcn); + prevre = 0; /* working on first RE */ + reoff = 0; + dcn = startdcn; /* start filling in RE's here */ + for (clu = 0; clu < clucount; clu++) + { + if (reoff == 0) /* time to get another RE */ + { + if ((re = getent ()) == 0) + { + for (clu = 0; clu < clucount; clu++) + retclu (startdcn + (clu * dcnperfcs), f->clusiz); + retfile (f->nlink); + return (FALSE); + } + if (sw.debug != NULL) + printf ("crefile() re at %o\n", re); + if (prevre) + { + readlk (prevre); + use(ufdre,k)->ulnk = re; + } + else + { + readlk (f->nlink); + use(ufdne,k)->uar = re; + f->rlink = re; /* save in firqb */ + } + MARKF; + prevre = re; /* next RE will link to this */ + readlk (re); /* read it */ + } + use(ufdre,k)->uent[reoff++] = dcn; + MARKF; + dcn += dcnperfcs; /* point to next file cluster */ + if (reoff > 6) reoff = 0; /* check for end of RE */ + } + } + readlk (f->nlink); /* read NE again */ + use(ufdne,k)->ulnk = nextlink; /* link it to next */ + MARKF; + readlk2 (prevlink); /* read previous */ + use(ufdne,k)->ulnk = f->nlink; /* link it to new file */ + MARKF; + prevlink = f->nlink; /* this is new previous */ + if (f->size) + updqb (f, UP(f->size,f->clusiz)); + return (TRUE); +} + +/* This routine checks whether a file is protected. It returns TRUE if so. + * It must be called after a call to nextfile or nextfileindir; the + * file information in the firqb is used to control the decisions. + */ + +int protfile (firqb *f) +{ + if (f->stat & us_nok) + { + printf ("File "); + printcurname (f); + printf (" is marked no-delete\n"); + return (TRUE); + } + if (sw.overwrite == NULL && f->prot & up_wpo) + { + printf ("File "); + printcurname (f); + printf (" is protected\n"); + return (TRUE); + } + return (FALSE); +} + +/* Makedir creates a new account. It allocates the GFD, if needed, and + * creates the accounting data for the specified PPN. It does not actually + * allocate a UFD; this will happen when a file is created there, or can + * be done at any time by calling allocufd. + * It returns TRUE on success, FALSE on failure. On failure, an explanatory + * message is also printed. + * The caller must verify that the account does not currently exist. curgfd + * must be set up to point to the gfd, if it exists. "initfilescan" can be + * used to do both these things. + */ + +/* the second (high order) 255 is overwritten with the project number */ + +ufdlabel newglabel = { 1, 0177777, {0, 0, 0, 0}, {255, 255}, GFD }; + +int makedir (firqb *f, int newclu) +{ + gfdne *n; + gfdae *a; + ua_quo *q; + ua_dat *d; + word ne, ae, quo, dat; + int gfdclu; + +/* note: when processing an RDS 0.0 disk, curgfd = mfdlbn = the start lbn + * of the MFD (DCN 1) + */ + + if (sw.debug != NULL) + { + printf ("makedir() for"); + printcurname (f); + printf ("\n"); + } + if (plevel == RDS0 && f->cproj == 0) + { + printf ("Invalid PPN [%d,%d] for RDS 0.0 format disk\n", f->cproj, f->cprog); + return (FALSE); + } + if (curgfd == 0) /* must create GFD */ + { + gfdclu = 4; + if (gfdclu < pcs) + gfdclu = pcs; + if (gfdclu > 16) + gfdclu = 16; + newglabel.lppn[1] = f->cproj; + if (!extdir2 (0, gfdclu, fd_new, &newglabel)) + { + printf ("No room to allocate GFD for [%d,*]\n", f->cproj); + return (FALSE); + } + curgfd = clumap->uent[0]; /* remember its DCN */ + fbread (mfdlbn + gfddcntbl); + fibufw[f->cproj] = curgfd; /* set new GFD pointer */ + MARKF; + curgfd = dcntolbn(curgfd); /* and remember the LBN */ + } + fbread (curgfd); /* read first block of GFD */ + entptr = sizeof (gfdlabel); /* initialize getent search */ + if ((ae = getent ()) == 0) + { + printf ("No room to create [%d,%d]\n", f->cproj, f->cprog); + return (FALSE); + } + readlk (ae); + a = use(gfdae,k); + a->ulnk = ul_use; + a->uclus = newclu; + MARKF; + if (plevel > RDS0) + { + if ((dat = getent ()) == 0) + { + printf ("No room to create [%d,%d]\n", f->cproj, f->cprog); + retent (ae); + return (FALSE); + } + readlk (dat); + d = use(ua_dat,k); + d->ulnk = ul_use; /* mark in use */ + d->uatyp = aa_dat; /* set type code */ + d->at_lti = at_npw; /* in case it's set to /user */ + d->at_cda = d->at_pda = curdate (); + d->at_pti = curtime () | at_nlk; /* set no-lookup flag */ + if (plevel >= RDS12) + d->at_exp = 65535U; + MARKF; + if ((quo = getent ()) == 0) + { + printf ("No room to create [%d,%d]\n", f->cproj, f->cprog); + retent (ae); + retent (dat); + return (FALSE); + } + readlk (quo); + q = use(ua_quo,k); + q->ulnk = dat; /* link to date/time */ + q->uatyp = aa_quo; /* set type code */ + q->aq_lol = 65535U; /* set disk quotas unlimited */ + q->aq_lil = 65535U; + q->aq_lom = 255U; + q->aq_lim = 255U; + MARKF; + } + if ((ne = getent ()) == 0) + { + printf ("No room to create [%d,%d]\n", f->cproj, f->cprog); + retent (ae); + if (plevel > RDS0) + { + retent (dat); + retent (quo); + } + return (FALSE); + } + readlk (ne); + n = use(gfdne,k); + n->unam[0] = (f->cproj << 8) + f->cprog; + n->ustat = us_nok | us_ufd; + n->uprot = 60; + n->uaa = ae; + MARKF; + if (plevel > RDS0) + { + n->ulnk = quo; /* link to quotas */ + fbread (curgfd + gfdatrtbl); /* read GFD table block */ + fibufw[f->cprog] = ne; /* set NE link */ + } + else + { + n->ulnk = nextppnlink; /* link this one to next */ + readlk2 (prevppnlink); /* read previous MFD NE */ + use(gfdne,k)->ulnk = ne; /* and link it to new NE */ + prevppnlink = ne; /* this is previous next time */ + } + MARKF; + return (TRUE); +} + +/* remdir removes a directory, or prints a message explaining why + * it can't. Returns TRUE on success, FALSE on failure. The name entry + * link for the PPN is supplied by the caller. + * + */ + +int remdir (firqb *f, word ne) +{ + word ae, attr, a2; + long savelbn, ufdclu; + gfdne *n; + int j; + + if (f->cproj == 0 && f->cprog == 1) + { + printf ("Directory [0,1] cannot be deleted\n"); + return (FALSE); + } + readlk (ne); /* read its NE */ + n = use(gfdne,k); + if (n->uar) /* it has a UFD */ + { + savelbn = fiblk; + readdcn(n->uar); /* read the UFD */ + if (!NULLINK(use(ufdlabel,0)->ulnk)) + { + printf ("Directory [%d,%d] is not empty\n", + f->cproj, f->cprog); + fbread (savelbn); + return (FALSE); + } + ufdclu = clumap->uclus; /* get clustersize */ + if (ufdclu < pcs) + ufdclu = pcs; /* for big disks */ + for (j = 0; j < 7; j++) + if (clumap->uent[j]) + retclu (clumap->uent[j], ufdclu); + fbread (curgfd + gfddcntbl); /* read UFD pointer table */ + fibufw[f->cprog] = 0; /* no more UFD */ + MARKF; + fbread (savelbn); /* restore GFD block */ + } + ae = n->uaa; + attr = n->ulnk; + if (NULLINK(ae)) + rabort(CORRUPT); + retent (ne); /* release NE */ + retent (ae); /* and AE */ + if (plevel > RDS0) + { + while (!NULLINK (attr)) + { + readlk (attr); + a2 = use(uattr,k)->ulnk; /* remember next link */ + retent (attr); /* release it */ + attr = a2; + } + fbread (curgfd + gfdatrtbl); + fibufw[f->cprog] = 0; /* no more PPN */ + } + else + { + readlk2 (prevppnlink); /* read previous MFD NE */ + use(gfdne,k)->ulnk = nextppnlink; /* and unlink this one */ + } + MARKF; + return (TRUE); +} + +/* Set up the SATT parameters by searching for [0,1]satt.sys if that + * hasn't been done yet. + */ + +void findsat (void) +{ + firqb f; + + if (sattsize) return; /* don't do it twice */ + if (!findfile (&f, "[0,1]satt.sys")) + { + printf ("SATT.SYS not found\n"); + rabort(CORRUPT); + } + if ((f.stat & us_nox) == 0) + { + printf ("SATT.SYS is not contiguous\n"); + rabort(CORRUPT); + } + pcns = (diskblocks - dcs)/ pcs; /* pack size in pack clusters */ + sattsize = UP(pcns,BLKSIZE*8); /* round up to block boundary */ + sattsize /= BLKSIZE * 8; /* and change bits to blocks */ + if (f.size != sattsize) + { + printf ("Expected SATT.SYS size is %d, actual size is %ld\n", + sattsize, f.size); + rabort(CORRUPT); + } + sattsize *= BLKSIZE; /* now size in bytes */ + if ((sattbufp = (byte *) malloc (sattsize)) == NULL) rabort(NOMEM); + readlk (f.rlink); + sattlbn = dcntolbn(use(ufdre,k)->uent[0]); + rread (sattlbn, sattsize, sattbufp); + satptr = 0; /* nothing allocated yet */ +} + +void rmount (void) /* "mount" the rsts pack */ +{ + ropen (DREADMODE); /* open it first */ + readlabel (); /* read and remember label data */ + if (pflags & uc_mnt) + printf ("** warning: disk was not properly dismounted **\n"); + sattsize = 0; /* SATT not looked up yet */ + womsat = FALSE; /* and SATT is clean */ + fiblkw = FALSE; /* FIBUF ditto */ +} + +void rmountrw (void) /* mount the RSTS pack read/write */ +{ + packlabel *p; + + if (sw.debug != NULL) + printf ("rmountrw()\n"); + ropen (DWRITEMODE); /* open it first */ + readlabel (); /* read and remember label data */ + if (pflags & uc_mnt) + rabort(DIRTY); + if ((pflags & uc_ro) && (sw.overwrite == NULL)) + rabort(ROPACK); + sattsize = 0; /* SATT not looked up yet */ + womsat = FALSE; /* and SATT is clean */ + fiblkw = FALSE; /* FIBUF ditto */ + findsat (); /* make sure we know where satt is */ + readdcn (1); /* read the pack label */ + p = use(packlabel,0); + p->pstat |= uc_mnt; /* mark mounted */ + if (plevel >= RDS12) /* if new pack */ + { + p->mntdat = curdate (); /* update timestamps */ + p->mnttim = curtime (); + } + fbwrite (); /* write it back */ +} + +void rumount (void) /* dismount for users of rmount() */ +{ + rclose (); /* close the device */ +} + +void rumountrw (void) /* dismount (no longer read/write) */ +{ + packlabel *p; + + if (sw.debug != NULL) + printf ("rumount()\n"); + readdcn (1); /* read the pack label */ + p = use(packlabel,0); + if ((p->pstat & uc_mnt) == 0) + rabort(INTERNAL); + if (womsat) + rwrite (sattlbn, sattsize, sattbufp); + womsat = FALSE; /* SATT written out if needed */ + free (sattbufp); /* release satt memory copy */ + p->pstat &= ~uc_mnt; /* mark no longer mounted */ + if (plevel >= RDS12) /* if new pack */ + { + p->mntdat = curdate (); /* update timestamps */ + p->mnttim = curtime (); + } + fbwrite (); /* write it back */ + /* this leaves FIBUF clean */ + rumount (); /* now do common dismount */ +} diff --git a/extracters/rstsflx/fip.h b/extracters/rstsflx/fip.h new file mode 100644 index 0000000..6b804b9 --- /dev/null +++ b/extracters/rstsflx/fip.h @@ -0,0 +1,87 @@ +extern void fbwrite(void); +extern void checkwrite(void); +extern void fbread(long block); +extern void readdcn(long dcn); +extern int ulk(word link); + /* Prototype include a typedef name. + It should be moved after the typedef declaration */ +extern void readlk2(word link); + /* Prototype include a typedef name. + It should be moved after the typedef declaration */ +extern int readlk(word link); + /* Prototype include a typedef name. + It should be moved after the typedef declaration */ +extern int readlktbl(word link); + /* Prototype include a typedef name. + It should be moved after the typedef declaration */ +extern long scanbytes(long start , long last , int clusiz , long clucount); +extern long scanbits(long start , long last , int clusiz , long clucount); +extern long getclu(int clusiz , long size); +extern void retclu(long pos , int clusiz); +extern void readlabel(void); +extern void setppn(firqb * f , int proj , int prog , word ppnent , int which); + /* Prototype include a typedef name. + It should be moved after the typedef declaration */ +extern word nextppn(firqb * f , int which); + /* Prototype include a typedef name. + It should be moved after the typedef declaration */ +extern word initfilescan(firqb * f , int which); + /* Prototype include a typedef name. + It should be moved after the typedef declaration */ +extern int wmatch(const char * wn , const char * n); +extern int nextfileindir(firqb * f); + /* Prototype include a typedef name. + It should be moved after the typedef declaration */ +extern int nextfile(firqb * f); + /* Prototype include a typedef name. + It should be moved after the typedef declaration */ +extern int findfile(firqb * f , const char * name); + /* Prototype include a typedef name. + It should be moved after the typedef declaration */ +extern int findqb(const firqb * f); + /* Prototype include a typedef name. + It should be moved after the typedef declaration */ +extern void updqb(const firqb * f , long delta); + /* Prototype include a typedef name. + It should be moved after the typedef declaration */ +extern void upddlw(const firqb * f); + /* Prototype include a typedef name. + It should be moved after the typedef declaration */ +extern void upddla(const firqb * f); + /* Prototype include a typedef name. + It should be moved after the typedef declaration */ +extern int extdir2(int newcm , int clusiz , byte flags , const ufdlabel * newl); + /* Prototype include a typedef name. + It should be moved after the typedef declaration */ +extern int extdir(void); +extern int allocufd(word dirne , firqb * f); + /* Prototype include a typedef name. + It should be moved after the typedef declaration */ +extern int getent(void); +extern void retent(word link); + /* Prototype include a typedef name. + It should be moved after the typedef declaration */ +extern void retfile(word nlink); + /* Prototype include a typedef name. + It should be moved after the typedef declaration */ +extern void delfile(firqb * f); + /* Prototype include a typedef name. + It should be moved after the typedef declaration */ +extern int crefile(firqb * f , const word16 * rtsname, + const ufdrms1 *rms1, const ufdrms2 *rms2); + /* Prototype include a typedef name. + It should be moved after the typedef declaration */ +extern int protfile(firqb * f); + /* Prototype include a typedef name. + It should be moved after the typedef declaration */ +extern int makedir(firqb * f , int newclu); + /* Prototype include a typedef name. + It should be moved after the typedef declaration */ +extern int remdir(firqb * f , word ne); + /* Prototype include a typedef name. + It should be moved after the typedef declaration */ +extern void findsat(void); +extern void rmount(void); +extern void rmountrw(void); +extern void rumount(void); +extern void rumountrw(void); diff --git a/extracters/rstsflx/fldef.h b/extracters/rstsflx/fldef.h new file mode 100644 index 0000000..95db67d --- /dev/null +++ b/extracters/rstsflx/fldef.h @@ -0,0 +1,299 @@ +/* fldef.h -- RSTS file system definitions + * + * Derived from fldef.mac, RSTS V10.1. + */ + +/* rad50 constants we need */ +#define MFD 0051064 /* rad50 "MFD" */ +#define GFD 0026264 /* rad50 "GFD" */ +#define UFD 0102064 /* rad50 "UFD" */ +#define TMP 0077430 /* rad50 "TMP" */ + +/* Disk file structure definitions + * Any definitions that apply only for certain disk structure levels + * are marked accordingly. They apply to the rev level stated and those + * after it. + */ + +/* Note: except for the pack label, each of these struct definitions + * must define a struct of size 16 bytes. + */ + +typedef struct { /* Pack label entry */ + word16 ulnk; /* Link if RDS0.0, otherwise 1 */ + int16 fill1; /* Reserved (-1) */ + word16 mdcn; /* Starting DCN of MFD (RDS1.1) */ + word16 plvl; /* Pack revision level */ + word16 ppcs; /* Pack cluster size */ + word16 pstat; /* Pack status/flags */ + word16 pckid[2]; /* Pack ID */ + word16 tapgvn[2]; /* TAP generation-version number (RDS1.1) */ + word16 bckdat; /* Date of last TAP full backup (RDS1.1) */ + word16 bcktim; /* Time of last TAP full backup (RDS1.1) */ + word16 mntdat; /* Date of last mount/dismount (RDS1.2) */ + word16 mnttim; /* Time of last mount/dismount (RDS1.2) */ + byte fill2[BLKSIZE-(14*sizeof(word16))]; /* Reserved */ +} packlabel; + +/* Flag bits in pack label field */ + +#define uc_top 0001000 /* New files first */ +#define uc_dlw 0004000 /* Maintain date of last write */ +#define uc_ro 0010000 /* Read-only pack */ +#define uc_new 0020000 /* "New" pack (RDS1.1) */ +#define uc_pri 0040000 /* Pack is private/system */ +#define uc_mnt 0100000 /* Pack is mounted (dirty) */ + +/* Rev levels */ +#define RDS0 0 /* RDS 0 -- V7.x and before */ +#define RDS11 ((1<<8)+1) /* RDS 1.1 -- V8 */ +#define RDS12 ((1<<8)+2) /* RDS 1.2 -- V9.0 and beyond */ + +/* MFD and GFD are new as of RDS1.1 */ + +typedef struct { /* MFD label entry */ + word16 fill1; /* Reserved (0) */ + int16 fill2; /* Reserved (-1) */ + word16 fill3[3]; /* Reserved (0) */ + word16 malnk; /* Link to pack attributes */ + byte lppn[2]; /* PPN [255,255] */ + word16 lid; /* Identification (RAD50 "MFD") */ +} mfdlabel; + +typedef struct { /* Directory cluster map */ + byte uclus; /* Directory clustersize */ + byte uflag; /* RDS1 GFD/MFD flag in high bit */ + word16 uent[7]; /* The dcn's of the cluster(s) */ +} fdcm; + +#define fd_new 0200 /* flag bit for GFD/MFD in uflag (RDS1.1) */ + +typedef struct { /* GFD label entry */ + word16 fill1; /* Reserved (0) */ + int16 fill2; /* Reserved (-1) */ + word16 fill3[4]; /* Reserved (0) */ + byte lppn[2]; /* PPN [x,255] */ + word16 lid; /* Identification (RAD50 "GFD") */ +} gfdlabel; + +/* mfd/gfd offsets */ +#define gfddcntbl 1 /* block with DCN pointer table */ +#define gfdatrtbl 2 /* block with attribute link table */ + +/* For RDS0, the "GFD NE" and "GFD AE" live in the MFD ([1,1] directory) + * which starts at DCN 1. They are in a linked list, possibly mixed + * with files, in the usual UFD fashion. + */ + +typedef struct { /* GFD name entry */ + word16 ulnk; /* Link to attributes */ + word16 unam[3]; /* PPN and password */ + byte ustat; /* Status byte */ + byte uprot; /* Protection code */ + word16 uacnt; /* Access count */ + word16 uaa; /* Link to accounting entry */ + word16 uar; /* Dcn of start of UFD */ +} gfdne; + +typedef struct { /* GFD accounting entry */ + word16 ulnk; /* Flags */ + word16 mcpu; /* Accum cpu time (LSB) */ + word16 mcon; /* Accum connect time */ + word16 mkct; /* Accum kct's (LSB) */ + word16 mdev; /* Accum device time */ + word16 mmsb; /* Accum cpu time and kct's (MSB's) */ + word16 mdper; /* Disk quota */ + word16 uclus; /* UFD cluster size */ +} gfdae; + +typedef struct { /* UFD label entry */ + word16 ulnk; /* Link to first name block in UFD */ + int16 fill2; /* Reserved (-1) */ + word16 fill3[4]; /* Reserved (0) */ + byte lppn[2]; /* PPN [x,y] */ + word16 lid; /* Identification (RAD50 "UFD") */ +} ufdlabel; + +typedef struct { /* UFD name entry */ + word16 ulnk; /* Link to next name entry */ + word16 unam[3]; /* File name and extension */ + byte ustat; /* Status byte */ + byte uprot; /* Protection code */ + word16 uacnt; /* Access count */ + word16 uaa; /* Link to UFD accounting entry */ + word16 uar; /* Link to retrieval entries */ +} ufdne; + +typedef struct { /* UFD accounting entry */ + word16 ulnk; /* Link to attributes and flags */ + word16 udla; /* Date of last access (or write) */ + word16 usiz; /* File size */ + word16 udc; /* Date of creation */ + word16 utc; /* Time of creation */ + word16 urts[2]; /* File's run-time system name or 0/MSB size */ + word16 uclus; /* File cluster size */ +} ufdae; + +typedef struct { /* UFD first RMS attribute blockette */ + word16 ulnk; /* Link to second attributes blockette */ + word16 fa_typ; /* File type (rfm, org, rat) */ + word16 fa_rsz; /* Record size */ + word16 fa_siz[2]; /* File size (32 bits) */ + word16 fa_eof[2]; /* File EOF block number (32 bits) */ + word16 fa_eofb; /* EOF byte offset */ +} ufdrms1; + +#define fa_rfm 0000007 /* record format field in fa_typ */ +#define rf_udf 0 /* undefined organization */ +#define rf_fix 1 /* fixed length records */ +#define rf_var 2 /* variable length records */ +#define rf_vfc 3 /* variable with fixed control header */ +#define rf_stm 4 /* stream (cr/lf delimiter) */ +#define fa_org 0000070 /* file organization format in fa_typ */ +#define fo_seq 000 /* sequential organization */ +#define fo_rel 020 /* relative organization */ +#define fo_idx 040 /* indexed organization */ +#define fa_rat 0007700 /* record attribute flags */ +#define ra_ftn 0000400 /* fortran carriage control */ +#define ra_imp 0001000 /* implied carriage control */ +#define ra_spn 0004000 /* no-span records */ + +typedef struct { /* UFD second RMS attribute blockette */ + word16 ulnk; /* Link (reserved) */ + byte fa_bkt; /* Bucket size */ + byte fa_hsz; /* Header size */ + word16 fa_msz; /* Max record size */ + word16 fa_ext; /* Default extension amount */ + word16 filler[4]; /* Reserved */ +} ufdrms2; + +/* All directory attributes are new as of RDS1.1 or later */ + +typedef struct { /* MFD/GFD attribute entry */ + word16 ulnk; /* Link to next, flags */ + byte uatyp; /* Type */ + byte uadat[16-3]; /* Data */ +} uattr; + +/* Time of creation flag bit definitions */ + +#define utc_tm 0003777 /* Bits needed for the time field */ +#define utc_ig 0004000 /* IGNORE flag (RDS1.2) */ +#define utc_bk 0010000 /* NOBACKUP flag (RDS1.2) */ + /* Other bits reserved */ + +typedef struct { /* UFD retrieval entry */ + word16 ulnk; /* Link to next retrieval entry */ + word16 uent[7]; /* The dcn's of the cluster(s) */ +} ufdre; + +/* Bit assignments in ustat and f$stat */ + +#define us_out 0001 /* File is 'out of sat' (historical) */ +#define us_plc 0002 /* File is "placed" */ +#define us_wrt 0004 /* Write access given out (not on disk if large files) */ +#define us_upd 0010 /* File open in update mode (not on disk if large files) */ +#define us_nox 0020 /* No file extending allowed (contiguous) */ +#define us_nok 0040 /* No delete and/or rename allowed */ +#define us_ufd 0100 /* Entry is MFD type entry */ +#define us_del 0200 /* File marked for deletion */ + +/* Bit assignments in uprot and f$prot */ + +#define up_rpo 0001 /* Read protect against owner */ +#define up_wpo 0002 /* Write " " " */ +#define up_rpg 0004 /* Read " " group */ +#define up_wpg 0010 /* Write " " " */ +#define up_rpw 0020 /* Read " " world */ +#define up_wpw 0040 /* Write " " " */ +#define up_run 0100 /* Executable file */ +#define up_prv 0200 /* Clear on delete, privileged if executable file */ + +/* Link and flag word fields */ + +#define ul_use 0000001 /* On to ensure entry is "in use" */ +#define ul_bad 0000002 /* Some bad block exists in file */ +#define ul_che 0000004 /* Cache (name entry) or sequential (accting entry) */ +#define ul_cln 0000010 /* Reserved for 'clean' */ +#define ul_eno 0000760 /* Entry offset within block (5 bits) */ +#define ul_clo 0007000 /* Cluster offset within UFD (3 bits) */ +#define ul_blo 0170000 /* Block offset within cluster (4 bits) */ +#define sl_clo 9 /* Shift count for ul_clo field */ +#define sl_blo 12 /* shift count for ul_blo field */ + +#define LINKBITS (ul_eno | ul_clo | ul_blo) /* bits to test for null */ +#define NULLINK(l) (((l) & LINKBITS) == 0) + +/* Account attribute codes */ + +#define aa_quo 1 /* Quotas */ +#define aa_prv 2 /* Privilege masks */ +#define aa_pas 3 /* Password */ +#define aa_dat 4 /* Date/time recording (creation, change, login) */ +#define aa_nam 5 /* User name (RDS1.2) */ +#define aa_qt2 6 /* Quotas part 2 (RDS1.2) */ + +/* Attribute blockette layouts */ + +typedef struct { /* Disk Quota Attribute Blockette */ + word16 ulnk; /* Link to next, flags */ + byte uatyp; /* Type */ + byte aq_djb; /* Detached job quota */ + word16 aq_lol; /* Logged out quota (LSB) */ + word16 aq_lil; /* Logged in quota (LSB) */ + byte aq_lim; /* Logged in quota (MSB) */ + byte aq_lom; /* Logged out quota (MSB) */ + byte aq_rsm; /* Reserved */ + byte aq_crm; /* Current usage (MSB) */ + word16 aq_rsl; /* Reserved */ + word16 aq_crl; /* Current usage (LSB) */ +} ua_quo; + +#define privsz 6 /* number of privilege bytes */ + +typedef struct { /* Privilege mask data */ + word16 ulnk; /* Link to next, flags */ + byte uatyp; /* Type */ + byte fill1; /* Filler */ + byte ap_prv[privsz]; /* Authorized privileges */ + byte fill2[020-privsz-1-3]; /* Filler */ +} ua_prv; + +typedef struct { /* Date/time data */ + word16 ulnk; /* Link to next, flags */ + byte uatyp; /* Type */ + byte at_kb; /* Keyboard of last login */ + word16 at_lda; /* Date of last login */ + word16 at_lti; /* Time of last login */ + word16 at_pda; /* Date of last password16 change */ + word16 at_pti; /* Time of last password change */ + word16 at_cda; /* Date of creation */ + word16 at_exp; /* Expiration date (RDS1.2) */ + /* Account creation time (RDS1.1 only) */ +} ua_dat; + +/* Fields within at_lti */ +#define at_msk 0003777 /* Bits needed for the time field */ +#define at_npw 0004000 /* No password required */ + /* Other bits reserved */ + +/* Fields within at_pti */ +/* at_msk 0003777 * Bits needed for the time field */ +#define at_nlk 0004000 /* Not readable password if set */ +#define at_ndl 0010000 /* No-dialups flag */ +#define at_nnt 0020000 /* No-network flag */ +#define at_nlg 0040000 /* No-login account */ +#define at_cap 0100000 /* Captive account */ + +typedef struct { /* Second quota and date/time block */ + word16 ulnk; /* Link to next, flags */ + byte uatyp; /* Type */ + byte a2_job; /* Total job quota */ + word16 a2_rib; /* RIB quota */ + word16 a2_msg; /* Message limit quota */ + word16 fill1; /* Reserved */ + byte fill2; /* Reserved */ + byte a2_pwf; /* Password failed count */ + word16 a2_ndt; /* Date of Last non-interactive login */ + word16 a2_nti; /* Time of Last non-interactive login */ +} ua_qt2; diff --git a/extracters/rstsflx/flx.dep b/extracters/rstsflx/flx.dep new file mode 100644 index 0000000..1c812ae --- /dev/null +++ b/extracters/rstsflx/flx.dep @@ -0,0 +1,45 @@ +rstsflx.o: rstsflx.c version.h flx.h rstsflx.h platform.h fldef.h \ + scancmd.h diskio.h +fip.o: fip.c flx.h rstsflx.h platform.h fldef.h fip.h diskio.h rtime.h \ + filename.h +rtime.o: rtime.c flx.h rstsflx.h platform.h rtime.h fldef.h +filename.o: filename.c flx.h rstsflx.h platform.h filename.h fldef.h +doget.o: doget.c flx.h rstsflx.h platform.h fldef.h doget.h fip.h \ + filename.h fileio.h scancmd.h +dolist.o: dolist.c flx.h rstsflx.h platform.h fldef.h dolist.h fip.h \ + rtime.h filename.h scancmd.h +doalloc.o: doalloc.c flx.h rstsflx.h platform.h fldef.h doalloc.h fip.h +docomp.o: docomp.c flx.h rstsflx.h platform.h fldef.h docomp.h diskio.h \ + fip.h +dotype.o: dotype.c flx.h rstsflx.h platform.h fldef.h dotype.h fip.h \ + filename.h fileio.h scancmd.h +doput.o: doput.c flx.h rstsflx.h platform.h fldef.h doput.h fip.h \ + filename.h fileio.h scancmd.h +dodump.o: dodump.c flx.h rstsflx.h platform.h fldef.h dodump.h fip.h \ + filename.h diskio.h fileio.h scancmd.h +dodelete.o: dodelete.c flx.h rstsflx.h platform.h fldef.h dodelete.h \ + fip.h filename.h fileio.h scancmd.h +dorename.o: dorename.c flx.h rstsflx.h platform.h fldef.h dorename.h \ + fip.h filename.h fileio.h scancmd.h +dorts.o: dorts.c flx.h rstsflx.h platform.h fldef.h dorts.h fip.h \ + filename.h fileio.h scancmd.h +doprot.o: doprot.c flx.h rstsflx.h platform.h fldef.h doprot.h fip.h \ + filename.h fileio.h scancmd.h +dodir.o: dodir.c flx.h rstsflx.h platform.h fldef.h dodir.h fip.h \ + filename.h +doident.o: doident.c flx.h rstsflx.h platform.h fldef.h doident.h fip.h \ + rtime.h +doinit.o: doinit.c flx.h rstsflx.h platform.h fldef.h doinit.h fip.h \ + diskio.h filename.h +dohook.o: dohook.c flx.h rstsflx.h platform.h fldef.h silfmt.h dohook.h \ + fip.h filename.h fileio.h diskio.h +scancmd.o: scancmd.c flx.h rstsflx.h platform.h fldef.h silfmt.h \ + scancmd.h fip.h diskio.h filename.h doalloc.h doget.h doident.h \ + dolist.h dotype.h dodump.h doput.h dodelete.h dorename.h dorts.h \ + dodir.h doprot.h doinit.h dohook.h docomp.h doclean.h +doclean.o: doclean.c flx.h rstsflx.h platform.h fldef.h diskio.h \ + filename.h doclean.h fip.h rtime.h +fileio.o: fileio.c flx.h rstsflx.h platform.h fldef.h fileio.h filename.h \ + diskio.h fip.h +diskio.o: diskio.c flx.h rstsflx.h platform.h diskio.h absio.h +unxabsio.o: unxabsio.c flx.h rstsflx.h platform.h absio.h diff --git a/extracters/rstsflx/flx.doc b/extracters/rstsflx/flx.doc new file mode 100644 index 0000000..b80d3a3 Binary files /dev/null and b/extracters/rstsflx/flx.doc differ diff --git a/extracters/rstsflx/flx.h b/extracters/rstsflx/flx.h new file mode 100644 index 0000000..0008548 --- /dev/null +++ b/extracters/rstsflx/flx.h @@ -0,0 +1,227 @@ +/* rstsflx common definitions */ + +/* define BROKEN_ANSI when compiling on systems that have a defective + * set of include files, like SunOS 4.1 + */ +#ifdef BROKEN_ANSI +#define EXIT_SUCCESS 0 +#define EXIT_FAILURE 1 +#define strtoul strtol +#define SEEK_SET 0 +#define FILENAME_MAX 160 +#endif + +/* Apple doesn't define __unix__ */ +#ifdef __APPLE__ +#define __unix__ 1 +#endif + +#include "rstsflx.h" /* include mainline's prototypes */ + +/* macro to map a struct onto a given offset of fibuf */ + +#define use(str,off) ((str *)(&fibuf[(off)])) +#define clumap (use(fdcm,BLKSIZE-sizeof(fdcm))) +#define fibufw ((word16 *)(&fibuf[0])) + +/* block numbering conversions */ + +#define dcntolbn(dcn) ((dcn)*dcs) /* convert DCN to LBN */ +#define pcntolbn(pcn) ((pcn)*pcs+dcs) /* convert PCN to LBN */ +#define lbntodcn(lbn) ((lbn)/dcs) /* convert LBN to DCN */ +#define lbntopcn(lbn) (((lbn)-dcs)/pcs) /* convert LBN to PCN */ +#define dcntopcn(dcn) (((dcn)-1)*dcs/pcs) /* convert DCN to PCN */ +#define pcntodcn(pcn) ((pcn)*pcs/dcs+1) /* convert PCN to DCN */ + +/* other handy macros */ + +#define UP(x,y) (((x)+(y)-1)&(-(y))) /* round x up to mult of y */ +#define DOWN(x,y) ((x)&(-(y))) /* round x down to mult of y */ + +/* buffer marking */ + +#define MARKS (womsat = TRUE) /* mark SATT dirty */ +#define MARKF (fiblkw = TRUE) /* mark FIBUF dirty */ + +/* common constants */ + +#define FALSE 0 +#define TRUE 1 + +/* Useful general data types + * + * Note: "int" is being used here whenever 16 bits suffice; + * "long int" where 32 bits are needed. In some platforms, + * we'll end up with more bits than that, which is not a problem. + * Whenever data types of a specific size (rather than just a + * minimum size) are needed, the types defined in platform.h are used. + */ + +typedef unsigned char byte; +typedef unsigned int word; +typedef unsigned long int lword; + +/* bring in platform specific type definitions */ + +#include "platform.h" + +/* lengths of various strings, including null terminator */ + +#define NAMELEN 11 /* file name.ext */ +#define DATELEN 12 /* Y2k style date (4 digit year) */ +#define RTIMELEN 9 /* RSTS style time */ +#define RTSLEN 7 /* Runtime system name */ + +/* buffer sizes */ + +#define BLKSIZE 512 /* one disk block */ +#define LSIZE 512 /* length of line buffer */ + +/* error codes; sometimes return codes, sometimes fatal error codes */ + +#define BADRE 0 +#define BADLINK 1 +#define BADBLK 3 +#define BADDCS 4 +#define CORRUPT 5 +#define NOMEM 6 +#define INTERNAL 7 +#define DIRTY 8 +#define ROPACK 9 +#define DISKIO 10 +#define NOMSG 11 /* used when caller generates the message */ +#define BADPAK 12 /* pack cannot be rebuilt */ + +#define rabort(code) doabort (code, __FILE__, __LINE__) + +/* file scan codes for "dofiles" */ + +#define NOTNULL 0 +#define NULLISNULL 1 +#define NULLISWILD 2 + +/* open modes */ + +#define DREADMODE "rb" /* read only disk access */ +#define DWRITEMODE "r+b" /* read/write disk access */ +#define DCREATEMODE "w+b" /* creating new container file */ + +/* data types */ + +typedef struct { /* switch flag table layout */ + char *ascii; + char *bswitch; /* binary or brief (in list) */ + char *clusiz; + char *contig; + char *create; + char *rstsdevice; + char *debug; + char *end; + char *full; + char *merge; + char *oattr; + char *odt; + char *offset; + char *prot; + char *query; + char *replace; + char *rmsvar; + char *rmsfix; + char *rmsstm; + char *size; + char *disksize; + char *start; + char *summary; + char *tree; + char *unprot; + char *verbose; + char *wide; + char *overwrite; + char *narrow; + char *user; + char *hex; +} swtab; + +#define f_name 1 /* name present */ +#define f_namw 2 /* name wild */ +#define f_ext 4 /* extension present */ +#define f_extw 8 /* extension wild */ +#define f_ppn 16 /* PPN present */ +#define f_ppnw 32 /* PPN wild */ +#define f_prot 64 /* protection code present */ + +#define F_WILD (f_namw | f_extw | f_ppnw) /* something wild if set */ + +typedef struct { + long size; /* filesize */ + int clusiz; /* cluster size */ + int flags; /* parse flags */ + word nlink; /* link to NE */ + word alink; /* link to AE */ + word rlink; /* link to first RE */ + word rmslink; /* link to attributes */ + word recfmt; /* record format and flags for fileio */ + word recsiz; /* record size (if fixed records) */ + word rechdrsiz; /* header size if vfc */ + long eofblk; /* EOF block number from RMS */ + int eofbyte; /* EOF byte from RMS */ + word currecsiz; /* size of current (split across buffers) rec */ + word recskip; /* amount to skip for vfc */ + char *currec; /* current record pointer */ + byte stat; /* saved file status */ + byte prot; /* saved file protection */ + byte proj; /* supplied PPN as two bytes */ + byte prog; + char name[NAMELEN]; /* supplied file name.ext */ + byte newprot; /* protection code from filespec */ + byte cproj; /* current PPN as two bytes */ + byte cprog; + char cname[NAMELEN]; /* current name.ext */ +} firqb; /* well, sort of... :-) holds parsed filename */ + +/* typedefs for procedure datatypes, used to work around cc -protoi bug */ + +typedef void (*commandaction)(firqb *); +typedef void (*commandhandler)(int, char **); +typedef void (*iohandler)(long, long, void *); + +/* external references: */ + +extern swtab sw; /* switch and argument pointers */ +extern char *progname; /* name of this program */ +extern byte fibuf[BLKSIZE]; /* buffer for directories */ +extern byte *sattbufp; /* pointer to SATT buffer */ +extern int sattsize; /* size of SATT in bytes */ +extern long sattlbn; /* start LBN of SATT */ +extern long satptr; /* current allocation pointer (PCN) */ +extern int womsat; /* TRUE if SATT needs to be written */ +extern long fiblk; /* current block in FIBUF */ +extern int fiblkw; /* TRUE if FIBUF needs to be written */ +extern long i,k; /* current directory entry pointers */ +extern int pcs; /* pack clustersize */ +extern long pcns; /* number of pack clusters on this disk */ +extern int pflags; /* pack flags */ +extern int plevel; /* pack structure rev level */ +extern long mfddcn; /* DCN of start of MFD */ +extern long mfdlbn; /* LBN of start of MFD */ +extern char pname[7]; /* pack ID in ascii */ +extern int dcs; /* device clustersize */ +extern long diskblocks; /* device block count */ +extern const char *rname; /* file name of disk/container */ +extern const char *rssize; /* and size, as a string */ +extern long rsize; /* size of RSTS disk or container file */ +extern int absflag; /* flag for absolute I/O */ +extern FILE *rstsfile; /* file for the rsts disk/container */ +extern char **fargv; /* array of pointers to arguments */ +extern int fargc; /* and count of how many we found */ +extern char *iobuf; /* general file I/O buffer */ +extern long iobufsize; /* size of the buffer */ +extern int entptr; /* current directory entry allocation pointer */ +extern word nextlink; /* link to next file (ulnk of current) */ +extern word prevlink; /* link to predecessor file */ +extern word nextppnlink; /* link to next PPN for RDS 0 */ +extern word prevppnlink; /* link to prececessor of PPN for RDS 0 */ +extern long curgfd; /* LBN of start of current GFD */ +extern char *defdevice; /* default RSTS device name */ +extern char *defsize; /* and size */ +extern long newhistitems; /* new history items this session */ diff --git a/extracters/rstsflx/flx.pdf b/extracters/rstsflx/flx.pdf new file mode 100644 index 0000000..350f43b Binary files /dev/null and b/extracters/rstsflx/flx.pdf differ diff --git a/extracters/rstsflx/linuxabsio.c b/extracters/rstsflx/linuxabsio.c new file mode 100644 index 0000000..fa2be6a --- /dev/null +++ b/extracters/rstsflx/linuxabsio.c @@ -0,0 +1,233 @@ +/* absolute I/O support for Linux + * + * Paul Koning 95.01.05 created + * 99.12.31 updated for Linux (from generic unxabsio.c) + * 00.01.03 added size determination and geometry test + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "flx.h" +#include "absio.h" + +/* this routine is called to scan a supplied container file/device + * name. If the name refers to a real disk, then absflag is set + * and rsize is set to the device size. Otherwise, no action is taken. + * + * More precisely, there are three things this routine may want to do, + * depending on the OS and the name supplied. + * + * If, for the specified name, the absolute I/O routines in this module + * need to be called, then absflag should be set to TRUE, and rsize must + * be set to the size of the device. Otherwise, absflag should be left + * alone (which leaves it FALSE); that way the other absolute I/O routines + * in this module will not be called and standard C I/O is used instead. + * + * If, for the specified name, "fstat" will not return a size (i.e., returns + * zero) then rsize must specify the correct size. This can be set in this + * module, based on OS specific operations, or it can simply be left + * unchanged, in which case it has to be supplied by the user. + * + * For example, in Unix the fstat function doesn't return a size for raw + * devices (it returns zero) but the stdio routines are otherwise perfectly + * suitable. So this routine does NOT set absflag since no special abs I/O + * routines are needed. It does check the return from stat(); if this + * indicates a raw device, it checks that rsize has been supplied and + * complains if not. Note that the code below does not attempt to obtain + * the device size, since there is no portable Unix way of doing this that + * I know of. + */ + +static dev_t rdev; +static int floppy; +static byte trackbuf[BLKSIZE * 10]; +static int curtrack = -1; +static int writecurrent; + +static void makechs_rx50 (int block, int *trk, int *sec) +{ + int t, s; + + t = block / 10; + s = block % 10 + 1; + if (s < 6) s = (s - 1) * 2 + 1; + else s = (s - 5) * 2; + s += t * 2; + while (s > 10) s -= 10; + t++; + if (t == 80) t = 0; /* wrap around last 10 blocks */ + *trk = t; + *sec = s - 1; +} + +static void flushtrack (void) +{ + if (writecurrent) + { + lseek (floppy, curtrack * sizeof (trackbuf), SEEK_SET); + if (write (floppy, trackbuf, sizeof (trackbuf)) != + sizeof (trackbuf)) + doabort (DISKIO, __FILE__, __LINE__); + writecurrent = FALSE; + } +} + +static void gettrack (int track) +{ + if (track != curtrack) + { + flushtrack (); + lseek (floppy, track * sizeof (trackbuf), SEEK_SET); + if (read (floppy, trackbuf, sizeof (trackbuf)) != + sizeof (trackbuf)) + doabort (DISKIO, __FILE__, __LINE__); + curtrack = track; + } +} + +void absname (const char *rname) +{ + struct stat sbuf; + int fd, i = -1; + long size; + struct hd_geometry loc; + + if (stat (rname, &sbuf)) return; /* try to get info about device */ + diskblocks = UP(sbuf.st_size,BLKSIZE) / BLKSIZE; + if (diskblocks == 0) + { + if (S_ISBLK(sbuf.st_mode)) + { + fd = open (rname, O_RDONLY); + if (fd >= 0) + { + i = ioctl (fd, BLKGETSIZE, &size); + if (i >= 0) + diskblocks = size; + i = ioctl (fd, HDIO_GETGEO, &loc); + close (fd); + } + else + diskblocks = rsize; + /* user can always override autoconfigured size */ + if (rsize != 0) + diskblocks = rsize; + if (diskblocks == 0) + { + printf ("Size not specified for RSTS disk %s\n", rname); + exit (EXIT_FAILURE); + } + if (diskblocks == 800 && + (i < 0 || + (loc.cylinders == 80 && + loc.heads == 1))) + { + /* Looks like an RX50 floppy, turn on + * special handling + */ + if (sw.debug != NULL) + printf ("rx50 handling enabled\n"); + absflag = TRUE; + } + /* if size wasn't overridden in command line, + * use the size we found + */ + if (rsize == 0) + rsize = diskblocks; + } + else + { + printf ("RSTS disk container is null or not a block device\n"); + exit (EXIT_FAILURE); + } + } +} + +/* This routine is called to do any device open actions that may be needed. + * The "mode" argument is a standard C open mode. The return value is zero + * for success, non-zero for error. + */ + +int absopen (const char *rname, const char *mode) +{ + int flags; + + if (strcmp (mode, DREADMODE) == 0) + flags = O_RDONLY; + else + flags = O_RDWR; + floppy = open (rname, flags); + return (floppy < 0); + curtrack = -1; +} + +/* This routine is called to do a seek on a device. You can do it here + * or as part of the read/write, whichever is easier. This routine is + * called only if the I/O operations are changing between read and write, + * or are not sequential. So you would want to do the work here if your + * OS does implicit sequential I/O, and make this a NOP if the read and + * write primitives take an explicit block number. + */ + +void absseek (long block) +{ +} + +/* This routine is called to do any needed "close" actions for absolute I/O */ + +void absclose () +{ + flushtrack (); + close (floppy); + floppy = -1; +} + +/* This routine is called to do an absolute device read. The block number + * is supplied, even though it could have been derived from a preceding + * absseek call. This is because absseek is not called when sequential + * reads are done. + */ + +long absread (long sec, long count, void *buffer) +{ + int track, tsec; + byte *b = (byte *) buffer; + + while (count) + { + makechs_rx50 (sec, &track, &tsec); + gettrack (track); + memcpy (b, trackbuf + (BLKSIZE * tsec), BLKSIZE); + b += BLKSIZE; + count -= BLKSIZE; + sec++; + } + return 0; /* success */ +} + +/* This routine is called to do an absolute device write. */ + +long abswrite (long sec, long count, void *buffer) +{ + int track, tsec; + byte *b = (byte *) buffer; + + while (count) + { + makechs_rx50 (sec, &track, &tsec); + gettrack (track); + memcpy (trackbuf + (BLKSIZE * tsec), b, BLKSIZE); + writecurrent = TRUE; + b += BLKSIZE; + count -= BLKSIZE; + sec++; + } + return 0; /* success */ +} diff --git a/extracters/rstsflx/platform.h b/extracters/rstsflx/platform.h new file mode 100644 index 0000000..1829d99 --- /dev/null +++ b/extracters/rstsflx/platform.h @@ -0,0 +1,65 @@ +/* Platform specific typedefs + * + * This file defines data types used for accessing external data, + * i.e., stuff that is a specific size. You may need to edit this + * to make the field sizes work right for a particular platform. + * (Likely cases are noted below.) + */ + +/* We'll try to figure out the sizes automatically. If this doesn't + * work right, define SHORTSIZE, LONGSIZE, and INTSIZE to equal the + * size (in bytes) of "short int", "long int" and "int" respectively. + */ + +#include + +#ifndef SHORTSIZE +#if (SHRT_MAX == 0x7fff) +#define SHORTSIZE 2 +#else +#error "Please define SHORTSIZE" +#endif +#endif + +#ifndef INTSIZE +#if (INT_MAX == 0x7fff) +#define INTSIZE 2 +#else +#if (INT_MAX == 0x7fffffff) +#define INTSIZE 4 +#else +#error "Please define INTSIZE" +#endif +#endif +#endif + +#ifndef LONGSIZE +#if (LONG_MAX == 0x7fffffff) +#define LONGSIZE 4 +#else +#if (LONG_MAX == 0x7fffffffffffffff) +#define LONGSIZE 8 +#else +#error "Please define LONGSIZE" +#endif +#endif +#endif + +#if (SHORTSIZE == 2) +typedef unsigned short int word16; +typedef short int int16; +#else +#error "can't typedef 16-bit integers..." +#endif + +#if (LONGSIZE == 4) +typedef unsigned long int lword32; +typedef long int long32; +#else +#if (INTSIZE == 4) +typedef unsigned int lword32; +typedef int long32; +#else +#error "can't typedef 32-bit integers..." +#endif +#endif diff --git a/extracters/rstsflx/rstsflx.c b/extracters/rstsflx/rstsflx.c new file mode 100644 index 0000000..9b46234 --- /dev/null +++ b/extracters/rstsflx/rstsflx.c @@ -0,0 +1,166 @@ +/* Program to manipulate RSTS disks and disk container files */ + +#include "version.h" /* set version number */ + +/* system includes */ + +#include +#include +#include +#include + +#include +#include + +/* application specific includes */ + +#include "flx.h" /* common definitions */ +#include "rstsflx.h" +#include "fldef.h" /* RSTS file system definitions */ +#include "scancmd.h" +#include "diskio.h" + +#define IOBLOCKS 64 + +#define IOSIZE IOBLOCKS*BLKSIZE /* size of general I/O buffer */ +#define IOEXTRA 10 /* number of extra bytes to allocate */ + +char *iobuf; /* pointer to buffer */ +long iobufsize; /* and size we allocated */ +char *cmdbuf; /* command line from readline */ + +static jmp_buf mainbuf; + +void doabort(int status, const char *srcfile, int srcline) +{ + switch (status) + { + case BADRE: + printf ("Invalid retrieval entries for file\n"); + break; + case BADBLK: + printf ("Block number out of range\n"); + break; + case BADDCS: + printf ("Invalid DCS (device too big)\n"); + break; + case CORRUPT: + printf ("Corrupt disk structure\n"); + break; + case NOMEM: + printf ("malloc failure\n"); + break; + case DIRTY: + printf ("Disk was not properly dismounted\n"); + break; + case ROPACK: + printf ("Disk is read-only and -Write was not specified\n"); + break; + case DISKIO: + printf ("I/O error on RSTS disk\n"); + perror (progname); /* print details */ + break; + case NOMSG: + /* no message, caller did that */ + break; + case BADPAK: + printf ("Disk cannot be rebuilt\n"); + break; + case INTERNAL: + default: + printf ("Internal error in program...\n"); + } + /* if it looks like our problem, report where it happened */ + if (status != DIRTY && + status != ROPACK && + status != NOMSG && + status != BADPAK) + { + printf (" in module %s, line %d\n", srcfile, srcline); + } + longjmp (mainbuf, 1); +} + +int main (int argc, char **argv) +{ + int cmdlen; + char **cmdargv = NULL; /* for scanning command line */ + int cmdargc; + char *word; + void (*command)(int, char **); + int endian; + char *s; + + /* set initial abort handler */ + if (setjmp (mainbuf)) + { + exit (EXIT_FAILURE); + } + + endian = 0; + *((char *)&endian) = 'A'; +#if (INTSIZE == 2) + if (endian == 0x4100) +#else + if (endian == 0x41000000) +#endif + { + printf ("FLX is not supported on big endian systems\n"); + exit (EXIT_FAILURE); /* quit right now */ + } + else if (endian != 0x41) + { + printf ("Error in endian test: %08x\n", endian); + exit (EXIT_FAILURE); /* quit right now */ + } + progname = argv[0]; /* remember our name */ + if ((iobuf = (char *) malloc (IOSIZE + IOEXTRA)) == NULL) + rabort (NOMEM); + iobufsize = IOSIZE; + initialize_readline (); /* Bind our completer. */ + if (argc > 1) /* arguments on command line */ + { + if ((command = scanargs (argc, argv)) == NULL) + exit (EXIT_FAILURE); /* scan arguments */ + (*command) (fargc, fargv); /* go execute the command */ + if (command != dodisk) return 0; /* done, exit */ + } + else + { + setrname (); + printf ("FLX %s\nDefault RSTS disk is %s\n\n", IDENT, rname); + } + for (;;) + { + /* in the case of abort, we come back here */ + setjmp (mainbuf); + cmdbuf = readline ("flx> "); + if (cmdbuf == NULL) break; /* control-d to quit */ + s = stripwhite (cmdbuf); + if (*s) + { + add_history (s); + newhistitems++; + if (cmdargv != NULL) free (cmdargv); + if ((cmdargv = (char **) malloc (sizeof (char *))) == NULL) + rabort (NOMEM); + cmdargv[0] = progname; /* match conventions */ + cmdargc = 1; + word = strtok (s, " "); + while (word != NULL) + { + cmdargv = (char **) realloc (cmdargv, + ++cmdargc * sizeof (char *)); + if (cmdargv == NULL) rabort (NOMEM); + cmdargv[cmdargc - 1] = word; + word = strtok (NULL, " "); + } + if (cmdargc == 1) continue; /* ignore null command */ + /* go execute the command */ + if ((command = scanargs (cmdargc, cmdargv)) != NULL) + (*command)(fargc, fargv); + } + free (cmdbuf); + } + doexit (0, NULL); +} diff --git a/extracters/rstsflx/rstsflx.h b/extracters/rstsflx/rstsflx.h new file mode 100644 index 0000000..2aaede8 --- /dev/null +++ b/extracters/rstsflx/rstsflx.h @@ -0,0 +1,3 @@ +extern void doabort(int status , const char * srcfile , int srcline) + __attribute__ ((noreturn)); +extern int main(int argc , char **argv); diff --git a/extracters/rstsflx/rtime.c b/extracters/rstsflx/rtime.c new file mode 100644 index 0000000..c438afa --- /dev/null +++ b/extracters/rstsflx/rtime.c @@ -0,0 +1,76 @@ +/* subroutines to handle RSTS date/time */ + +#include +#include +#include + +#include "flx.h" +#include "rtime.h" +#include "fldef.h" + +static const char months[12][4] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; +static int days[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + +char *cvtdate (word date, char *buf) +{ + long day, yr; + int mon; + + if (date == 0) { /* no date present */ + memcpy (buf, " none ", DATELEN); + return (buf + DATELEN - 1); /* point to terminator */ + } + yr = (long)date / 1000 + 1970; + day = date % 1000; + if (yr & 3) days[1] = 28; + else days[1] = 29; /* check for leap year */ + for (mon = 0; mon < 12; mon++) { + if (day <= days[mon]) break; + day -= days[mon]; + } + sprintf (buf, "%2ld-%3s-%04ld", day, months[mon], yr); + return (buf + DATELEN - 1); /* point to terminator */ +} + +char *cvttime (word time, char *buf) +{ + int hour, min; + char m; + + time &= at_msk; /* mask out any flags */ + if (time == 0) { /* no time present */ + memcpy (buf, " none ", RTIMELEN); + return (buf + RTIMELEN - 1); /* point to terminator */ + } + time = 1440 - time; /* now time since midnight */ + hour = time / 60; + min = time % 60; + if (hour >= 12) { + hour -= 12; + m = 'p'; + } else m = 'a'; + if (hour == 0) hour = 12; + sprintf (buf, "%2d:%02d %1cm", hour, min, m); + return (buf + RTIMELEN - 1); /* point to terminator */ +} + +word curdate () /* current date in rsts form */ +{ + struct tm *tmb; + time_t now; + + time (&now); + tmb = localtime (&now); + return ((tmb->tm_year - 70) * 1000 + tmb->tm_yday + 1); +} + +word curtime () /* current time in rsts form */ +{ + struct tm *tmb; + time_t now; + + time (&now); + tmb = localtime (&now); + return (1440 - (tmb->tm_hour * 60 + tmb->tm_min)); +} diff --git a/extracters/rstsflx/rtime.h b/extracters/rstsflx/rtime.h new file mode 100644 index 0000000..612db41 --- /dev/null +++ b/extracters/rstsflx/rtime.h @@ -0,0 +1,12 @@ +extern char * cvtdate(word date , char * buf); + /* Prototype include a typedef name. + It should be moved after the typedef declaration */ +extern char * cvttime(word time , char * buf); + /* Prototype include a typedef name. + It should be moved after the typedef declaration */ +extern word curdate(void); + /* Prototype include a typedef name. + It should be moved after the typedef declaration */ +extern word curtime(void); + /* Prototype include a typedef name. + It should be moved after the typedef declaration */ diff --git a/extracters/rstsflx/scancmd.c b/extracters/rstsflx/scancmd.c new file mode 100644 index 0000000..f4f689c --- /dev/null +++ b/extracters/rstsflx/scancmd.c @@ -0,0 +1,577 @@ +/* command line handling for rstsflx */ + +#include +#include +#include +#include + +#include +#include + +/* Some unixes define this, some do not. */ +#ifndef whitespace +#define whitespace(c) ((c) == ' ' || (c) == '\t') +#endif + +#include "flx.h" +#include "fldef.h" +#include "silfmt.h" +#include "scancmd.h" +#include "fip.h" +#include "diskio.h" +#include "filename.h" +#include "doalloc.h" +#include "doget.h" +#include "doident.h" +#include "dolist.h" +#include "dotype.h" +#include "dodump.h" +#include "doput.h" +#include "dodelete.h" +#include "dorename.h" +#include "dorts.h" +#include "dodir.h" +#include "doprot.h" +#include "doinit.h" +#include "dohook.h" +#include "docomp.h" +#include "doclean.h" + +swtab sw; /* switch flag table */ + +char *progname; /* name of program (argv[0]) */ +char *cmdname; /* command name (argv[1]) */ +char **fargv = NULL; /* array of pointers to arguments */ +int fargc; /* and count of how many we found */ +char *defdevice = NULL; /* default device name */ +char *defsize = NULL; /* and size, as a string */ +char *histfile; /* name of history file */ +int hfilesize; /* size limit for history file */ +long newhistitems; /* number of history items added */ + +typedef struct { + const char *kw; + void (*hand)(int, char *[]); +} cmdent; + +/* This routine is used to ask (if -query was specified) whether a file + * should be processed or not. It returns the answer, which is a character + * "y", "n" or "q". Note that the answer "a" is returned as "y" and + * further prompting is turned off. + */ + +char doquery (void (*printfile)(void *), void *name) +{ + char answer[200]; + char first; + + if (sw.query == NULL) return ('y'); + else { + for (;;) { + printf (" %s ", cmdname); + (*printfile) (name); + printf (" (y,n,a,q)? "); + fflush (stdout); + fgets (answer, sizeof (answer), stdin); + first = tolower (answer[0]); + if (first == 'q' || first == 'n' || first == 'y') + return (first); + if (first == 'a') + { + sw.query = NULL; + return ('y'); + } + printf ("Invalid answer\n"); + } + } +} + +/* This routine is used as the generic main loop for many command + * processing routines. The first two arguments define the list of + * command (file) arguments. The third argument controls what to do + * if the name part of the filespec is null: + * NOTNULL error -- "missing filename" + * NULLISWILD ok, substitute wildcard ("?") for the missing name + * NULLISNULL ok, leave the name part null, so it's a directory + * reference -- and if it's [*,*] or [n,*], treat + * that as access to MFD and GFD respectively (rather + * than wild directories). + * + * -query switch processing is provided in this routine. If a command + * does not want -query to have effect, it should override the switch to + * be absent (sw.query = NULL). + */ + +void dofiles (int argc, char **argv, commandaction action, int nullflag) +{ + int fnum, j; + firqb f; + int matches; + char answer; + + if (argc == 0) printf ("Usage: %s %s files...\n", progname, cmdname); + for (fnum = 0; fnum < argc; fnum++) + { + if (!parse (argv[fnum], &f)) + { + printf ("Invalid filespec %s\n", argv[fnum]); + continue; + } + if (nullflag == NOTNULL && (f.flags & f_name) == 0) + { + printf ("Missing filename %s\n", argv[fnum]); + continue; + } + else if (nullflag == NULLISWILD) + { + if ((f.flags & f_name) == 0) + for (j = 0; j < 6; j++) f.name[j] = '?'; + f.flags |= f_name | f_namw; + if ((f.flags & f_ext) == 0) + { + f.name[7] = '?'; + f.name[8] = '?'; + f.name[9] = '?'; + f.flags |= f_ext | f_extw; + } + } + else if (nullflag == NULLISNULL && (f.flags & f_name) == 0) + { + if (f.prog == 255) + { + if (plevel == RDS0) + { + printf ("GFD or MFD not legal for RDS.0 pack\n"); + continue; + } + } + else if (f.proj == 255) + { + printf ("Invalid directory spec\n"); + continue; + } + } + matches = 0; + if (initfilescan (&f, gfddcntbl)) /* setup file scan */ + { + answer = 'y'; /* dummy */ + while (nextfile (&f)) + { + matches++; /* found another */ + answer = doquery ((void (*)(void *))printcurname, &f); + if (answer == 'q') break; + if (answer == 'n') continue; + (*action) (&f); /* do whatever */ + } + if (answer == 'q') break; /* out two levels... */ + } + if (matches == 0) + { + printf ("No files matching "); + printfqbname (&f); + printf ("\n"); + } + } +} + +void dodisk (int argc, char **argv) +{ + long rsize, tsize; + int flag; + + if (defdevice != NULL) free (defdevice); + if (defsize != NULL) free (defsize); + defdevice = NULL; + defsize = NULL; + if (argc > 0) + { + if (argc > 1) /* size also supplied */ + { + getsize (argv[1], &rsize, &tsize, &flag); + if (rsize == 0) + { + printf ("Invalid size %s\n", argv[1]); + return; + } + defdevice = (char *) malloc (strlen (argv[0]) + 1); + defsize = (char *) malloc (strlen (argv[1]) + 1); + if (defdevice == NULL || defsize == NULL) + rabort(NOMEM); + strcpy (defdevice, argv[0]); + strcpy (defsize, argv[1]); + } + else + { + defdevice = (char *) malloc (strlen (argv[0]) + 1); + if (defdevice == NULL) rabort(NOMEM); + strcpy (defdevice, argv[0]); + } + } + if (sw.verbose != NULL) + { + setrname (); + if (defsize != NULL) + printf ("Default RSTS disk name is %s, size %ld\n", + rname, rsize); + else printf ("Default RSTS disk name is %s\n", rname); + } +} + +void doexit (int argc, char **argv) +{ + int i; + +#ifndef __APPLE__ + i = append_history (newhistitems, histfile); + if (i) write_history (histfile); + else history_truncate_file (histfile, hfilesize); + free (histfile); +#endif + exit (EXIT_SUCCESS); +} + +const cmdent commands[] = +{ + { "list", dolist }, + { "directory", dolist }, + { "ls", dolist }, + { "type", dotype }, + { "cat", dotype }, + { "dump", dodump }, + { "exit", doexit }, + { "quit", doexit }, + { "bye", doexit }, + { "get", doget }, + { "put", doput }, + { "delete", dodelete }, + { "rm", dodelete }, + { "protect", doprot }, + { "rts", dorts }, + { "runtime", dorts }, + { "rename", dorename }, + { "mv", dorename }, + { "move", dorename }, + { "hook", dohook }, + { "mkdir", domkdir }, + { "rmdir", dormdir }, + { "identify", doident }, + { "allocation", doalloc }, + { "initialize", doinit }, + { "dskint", doinit }, + { "disk", dodisk }, + { "compress", docomp }, + { "clean", doclean }, + { "rebuild", doclean }, + { NULL, NULL } }; + +typedef struct +{ + char *kw; + char **flag; + int arg; /* TRUE if switch takes an argument */ +} swname; + +#define sd(x,y) { #x, &sw.y, FALSE } /* switch w/o arg */ +#define sda(x,y) { #x, &sw.y, TRUE } /* switch with arg */ + +const swname switches[] = +{ + sd(ascii,ascii), + sd(binary,bswitch), + sd(brief,bswitch), + sda(clustersize,clusiz), + sd(confirm,query), + sd(contiguous,contig), + sda(create,create), + sda(disk,rstsdevice), + sd(Debug,debug), + sda(end,end), + sda(filesize,size), + sd(full,full), + sd(image,bswitch), + sd(long,full), + sda(merge,merge), + sd(noprotect,unprot), + sd(oattributes,oattr), + sd(odt,odt), + sda(offset,offset), + sd(protect,prot), + sd(query,query), + sd(replace,replace), + sd(r,rmsvar), + sda(rf,rmsfix), + sd(rv,rmsvar), + sd(rs,rmsstm), + sda(size,size), + sda(Size,disksize), + sda(start,start), + sd(summary,summary), + sd(tree,tree), + sd(unprotect,unprot), + sd(verbose,verbose), + sd(wide, wide), + sd(Write,overwrite), + sd(1column,narrow), + sd(user,user), + sd(hex,hex), + { "", NULL, FALSE } }; + +commandhandler scanargs(int argc, char **argv) +{ + int n, l; + const cmdent *c; + const swname *s, *swn; + commandhandler command; + + memset (&sw, 0, sizeof (swtab)); /* Indicate no switches yet */ + if (fargv != NULL) free (fargv); + if ((fargv = (char **) malloc (argc * sizeof(char *))) == NULL) rabort (NOMEM); + fargc = 0; /* No arguments yet */ + cmdname = NULL; /* and no command name yet */ + for (n = 1; n < argc; n++) /* scan the program arguments */ + { + if (argv[n][0] == '-') /* it's a switch */ + { + s = switches; /* point to switch names */ + l = strlen (argv[n]) - 1; + swn = NULL; /* no match yet */ + while (s->flag != NULL) + { + if (strncmp (&argv[n][1], s->kw, l) == 0) { + if (strlen (s->kw) == l) + { + swn = s; + break; /* exact match */ + } + if (swn == NULL) swn = s; + else if (s->flag != swn->flag) + { + printf ("Ambiguous switch %s\n", + argv[n]); + return (NULL); + } + } + s++; + } + if (swn == NULL) + { + printf ("Unrecognized switch %s\n", argv[n]); + return (FALSE); + } + *(swn->flag) = argv[n]; + if (swn->arg) /* switch takes an argument */ + { + if (++n == argc) /* skip it */ + { + printf ("Missing argument for switch %s\n", argv[n - 1]); + return (FALSE); + } + *(swn->flag) = argv[n]; /* point to that */ + } + } + else + { + if (cmdname == NULL) cmdname = argv[n]; + else fargv[fargc++] = argv[n]; + } + + } + c = commands; + command = NULL; /* Nothing found yet */ + if (cmdname == NULL) + { + printf ("Missing command keyword\n"); + return NULL; + } + l = strlen (cmdname); /* get length of command */ + while (c->kw != NULL) /* look for matching command */ + { + if (strncmp (cmdname, c->kw, l) == 0) + { + if (strlen (c->kw) == l) + { + command = c->hand; + break; /* stop now on exact match */ + } + if (command == NULL) command = c->hand; + else if (command != c->hand) + { + printf ("Ambiguous command %s\n", cmdname); + return (NULL); + } + } + c++; + } + if (command == NULL) + { + printf ("Unrecognized command %s\n", cmdname); + return (NULL); + } + return (command); +} + +/* Strip whitespace from the start and end of STRING. Return a pointer + * into STRING. + */ +char *stripwhite (char *string) +{ + register char *s, *t; + + for (s = string; whitespace (*s); s++) ; + + if (*s == 0) return (s); + + t = s + strlen (s) - 1; + while (t > s && whitespace (*t)) t--; + *++t = '\0'; + + return s; +} + +/* **************************************************************** */ +/* */ +/* Interface to Readline Completion */ +/* */ +/* **************************************************************** */ + +/* some forward declarations */ +char * command_generator (const char *text, int state); +char * switch_generator (const char *text, int state); +char ** flx_completion (char *text, int start, int end); + +/* Tell the GNU Readline library how to complete. We want to try to complete + * on command names if this is the first word in the line, or on filenames + * if not. + */ +void initialize_readline (void) +{ + char *histfilesize; + char *histsize; + int hsize = 0; + char *home; + char *hf; + int i; + + /* get history parameters */ + hf = getenv ("FLXHISTFILE"); + histfilesize = getenv ("FLXHISTFILESIZE"); + histsize = getenv ("FLXHISTSIZE"); + hfilesize = 0; + newhistitems = 0; + if (hf == NULL) + { + home = getenv ("HOME"); + i = strlen (home); + histfile = malloc (i + strlen ("/.flx_history") + 1); + strcpy (histfile, home); + strcat (histfile, "/.flx_history"); + } + else histfile = strdup (hf); + if (histfilesize != NULL) hfilesize = atoi (histfilesize); + if (histsize != NULL) hsize = atoi (histsize); + if (hsize == 0) hsize = 100; + if (hfilesize == 0) hfilesize = hsize; + + /* set up history stuff */ + using_history (); + stifle_history (hsize); + read_history (histfile); + + /* Allow conditional parsing of the ~/.inputrc file. */ + rl_readline_name = "Flx"; + + /* Tell the completer that we want a crack first. */ + rl_attempted_completion_function = (CPPFunction *)flx_completion; + + /* supply some things that don't seem to be there in DOS... */ + rl_basic_word_break_characters = "n\"\\'`@$>"; + rl_completer_word_break_characters = + (char *) rl_basic_word_break_characters; +} + +/* Attempt to complete on the contents of TEXT. START and END show the + * region of TEXT that contains the word to complete. We can use the + * entire line in case we want to do some simple parsing. Return the + * array of matches, or NULL if there aren't any. + */ +char ** flx_completion (char *text, int start, int end) +{ + char **matches; + + matches = NULL; + + /* If this word is at the start of the line, then it is a command + * to complete. Otherwise it is the name of a file in the current + * directory. + */ + if (start == 0) + matches = rl_completion_matches (text, command_generator); + else if (*text == '-') + matches = rl_completion_matches (text, switch_generator); + + return (matches); +} + +/* Generator function for command completion. STATE lets us know whether + * to start from scratch; without any state (i.e. STATE == 0), then we + * start at the top of the list. + */ +char * command_generator (const char *text, int state) +{ + static int list_index, len; + char *name; + + /* If this is a new word to complete, initialize now. This includes + * saving the length of TEXT for efficiency, and initializing the index + * variable to 0. + */ + if (!state) + { + list_index = 0; + len = strlen (text); + } + + /* Return the next name which partially matches from the command list. */ + while ((name = (char *) commands[list_index].kw)) + { + list_index++; + if (strncmp (name, text, len) == 0) + return strdup (name); + } + + /* If no names matched, then return NULL. */ + return NULL; +} + +/* ditto but for switches */ +char * switch_generator (const char *text, int state) +{ + static int list_index, len; + char *name; + char sw[20]; + + /* If this is a new word to complete, initialize now. This includes + * saving the length of TEXT for efficiency, and initializing the index + * variable to 0. + */ + if (!state) + { + list_index = 0; + len = strlen (text) - 1; + } + + /* Return the next name which partially matches from the switch list. */ + while (*(name = switches[list_index].kw)) + { + list_index++; + if (strncmp (name, text + 1, len) == 0) + { + sw[0] = '-'; + strcpy (sw + 1, name); + return strdup (sw); + } + } + + /* If no names matched, then return NULL. */ + return NULL; +} diff --git a/extracters/rstsflx/scancmd.h b/extracters/rstsflx/scancmd.h new file mode 100644 index 0000000..20ba6b3 --- /dev/null +++ b/extracters/rstsflx/scancmd.h @@ -0,0 +1,11 @@ +extern char doquery (void (*printfile)(void *), void *name); +extern void dodisk (int argc, char **argv); +extern void dofiles(int argc , char **argv , commandaction action , int nullflag); + /* Prototype include a typedef name. + It should be moved after the typedef declaration */ +extern void doexit(int argc , char **argv); +extern commandhandler scanargs(int argc , char **argv); + /* Prototype include a typedef name. + It should be moved after the typedef declaration */ +extern void initialize_readline (void); +extern char *stripwhite (char *string); diff --git a/extracters/rstsflx/silfmt.h b/extracters/rstsflx/silfmt.h new file mode 100644 index 0000000..a0593e9 --- /dev/null +++ b/extracters/rstsflx/silfmt.h @@ -0,0 +1,87 @@ +/* + * Edit history for SILFMT + * + * [RSTS V9_0] + * 000 WJS 22-Sep-83 Creation + * + * [RSTS V9_6] + * 001 KPH 13-Nov-87 Increase number of phases to 47 + * + * 002 GPK 23-Aug-94 Convert from .mac to .h + * 003 GPK 29-Aug-94 Add definition for SAV format SIL index, add + * STB and overlay descriptor format. + */ + +/* Set the number of SIL index blocks allowed for this release */ + +#define si_nbl 3 /* Maximum number of SIL index blocks */ + +/* Definitions of SIL Index entry */ + +typedef struct { + word16 se_nam[2]; /* Name of module */ + word16 se_idn[2]; /* Ident of module */ + word16 se_blk; /* Starting block of module */ + word16 se_stb; /* Starting block of STB */ + word16 se_stn; /* Number of entries in STB */ + word16 se_lod; /* Load address of this module */ + word16 se_siz; /* Size of module (in bytes) */ + word16 se_xfr; /* Transfer address */ + word16 se_szd; /* Size of module image of disk in blocks */ + word16 se_ovb; /* Block offset to module's overlay descriptors */ + word16 se_ovn; /* Number of overlay descriptors for module */ + word16 se_off; /* Starting offset on disk for this module */ + word16 filler; /* (reserved) */ + word16 se_xxx; /* Reserved for SAV format SILs */ +} silent; + +#define se_len (sizeof (silent)) /* Size of SIL Index entry */ + +/* Derive the number of modules si_nbl SIL index blocks can contain */ + +#define si_oth (1000/se_len) /* Number of entries in a non-first block */ +#define si_1st (si_oth-1) /* Number of entries in first block */ +#define si_nmd ((si_nbl-1)*si_oth+si_1st) /* Maximum total no of index entries */ + +/* Layout for SIL index as it would be directly read from disk */ + +typedef struct { + word16 si_num; /* Number of modules in SIL */ + silent si_ent[si_1st]; /* Space for first block's SIL Index entries */ + word16 si_rsv[12]; /* Reserved */ + word16 si_bls; /* Size of this SIL in blocks */ + word16 si_chk; /* Checksum of SIL Index */ + word16 si_sil; /* RAD50 "SIL" for identification */ + silent si_mor[si_nmd - si_1st]; /* Space for non-first blocks' entries */ +} silindex; + +/* Layout for SIL index in the case of a .SAV file SIL */ + +typedef struct { + word16 si_num; /* Number of modules (must be 1) */ + silent si_ent; /* One SIL index entry */ +#define initpc si_ent.se_xxx /* Initial PC value lives here */ + word16 initsp; /* Initial SP */ + word16 rtjsw; /* Reserved for JSW in RT11 */ + word16 rtusr; /* Reserved for USR ptr in RT11 */ + word16 usertop; /* High address of program */ + word16 si_rsv[(0774-052)/2]; /* Fill to end of block */ + word16 si_chk; /* Checksum of SIL Index */ + word16 si_sil; /* RAD50 "SIL" for identification */ +} savsilindex; + +/* Layout of SIL symbol table entry */ + +typedef struct { + word16 name[2]; /* Symbol name in RAD50 */ + word16 ovnum; /* Overlay number */ + word16 value; /* Symbol value */ +} stbent; + +/* Layout of overlay descriptor entry */ + +typedef struct { + word16 base; /* Base virtual address of overlay */ + word16 size; /* Size in bytes of overlay */ + word16 offset[2]; /* Offset (MSW, LSW) to overlay */ +} ovrent; diff --git a/extracters/rstsflx/unxabsio.c b/extracters/rstsflx/unxabsio.c new file mode 100644 index 0000000..652895a --- /dev/null +++ b/extracters/rstsflx/unxabsio.c @@ -0,0 +1,110 @@ +/* absolute I/O support for Unix + * + * Paul Koning 95.01.05 created + * + * Note that this particular version of absio is mostly a dummy, since + * there is very little special that has to be done on Unix for absolute + * I/O. Among other things, this file should serve as a template for + * those who want to create the equivalent for another operating system. + */ + +#include +#include +#include +#include + +#include "flx.h" +#include "absio.h" + +/* this routine is called to scan a supplied container file/device + * name. If the name refers to a real disk, then absflag is set + * and rsize is set to the device size. Otherwise, no action is taken. + * + * More precisely, there are three things this routine may want to do, + * depending on the OS and the name supplied. + * + * If, for the specified name, the absolute I/O routines in this module + * need to be called, then absflag should be set to TRUE, and rsize must + * be set to the size of the device. Otherwise, absflag should be left + * alone (which leaves it FALSE); that way the other absolute I/O routines + * in this module will not be called and standard C I/O is used instead. + * + * If, for the specified name, "fstat" will not return a size (i.e., returns + * zero) then rsize must specify the correct size. This can be set in this + * module, based on OS specific operations, or it can simply be left + * unchanged, in which case it has to be supplied by the user. + * + * For example, in Unix the fstat function doesn't return a size for raw + * devices (it returns zero) but the stdio routines are otherwise perfectly + * suitable. So this routine does NOT set absflag since no special abs I/O + * routines are needed. It does check the return from stat(); if this + * indicates a raw device, it checks that rsize has been supplied and + * complains if not. Note that the code below does not attempt to obtain + * the device size, since there is no portable Unix way of doing this that + * I know of. + */ + +void absname (const char *rname) +{ + struct stat sbuf; + + if (stat (rname, &sbuf)) return; /* try to get info about device */ + diskblocks = UP(sbuf.st_size,BLKSIZE) / BLKSIZE; + if (diskblocks == 0) { + if (S_ISCHR(sbuf.st_mode)) { + diskblocks = rsize; + if (rsize == 0) { + printf ("Size not specified for RSTS disk %s\n", rname); + exit (EXIT_FAILURE); + } + } + } +} + +/* This routine is called to do any device open actions that may be needed. + * The "mode" argument is a standard C open mode. The return value is zero + * for success, non-zero for error. + */ + +int absopen (const char *rname, const char *mode) +{ + rabort(INTERNAL); /* should never get here */ +} + +/* This routine is called to do a seek on a device. You can do it here + * or as part of the read/write, whichever is easier. This routine is + * called only if the I/O operations are changing between read and write, + * or are not sequential. So you would want to do the work here if your + * OS does implicit sequential I/O, and make this a NOP if the read and + * write primitives take an explicit block number. + */ + +void absseek (long block) +{ + rabort(INTERNAL); /* should never get here */ +} + +/* This routine is called to do any needed "close" actions for absolute I/O */ + +void absclose () +{ + rabort(INTERNAL); /* should never get here */ +} + +/* This routine is called to do an absolute device read. The block number + * is supplied, even though it could have been derived from a preceding + * absseek call. This is because absseek is not called when sequential + * reads are done. + */ + +long absread (long sec, long count, void *buffer) +{ + return (0); /* should never get here */ +} + +/* This routine is called to do an absolute device write. */ + +long abswrite (long sec, long count, void *buffer) +{ + return (0); /* should never get here */ +} diff --git a/extracters/rstsflx/version.h b/extracters/rstsflx/version.h new file mode 100644 index 0000000..e16f0b0 --- /dev/null +++ b/extracters/rstsflx/version.h @@ -0,0 +1 @@ +#define IDENT "v2.6" /* program version number */