From 9eb5d725532b2e20f75dccce9112381348a870b7 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Thu, 21 May 2015 15:07:13 -0700 Subject: [PATCH] Import most recent simtools.zip and add a few extra tape converters --- README.md | 66 +++ converters/decsys.c | 69 +++ converters/hpconvert.c | 424 ++++++++++++++ converters/indent.c | 120 ++++ converters/m8376.c | 71 +++ converters/mt2tpc.c | 87 +++ converters/noff.c | 66 +++ converters/strrem.c | 72 +++ converters/strsub.c | 74 +++ converters/tar2mt.c | 92 +++ converters/tar2mt.txt | 25 + converters/tpc2mt.c | 84 +++ crossassemblers/hpasm.c | 930 ++++++++++++++++++++++++++++++ extracters/mtdump.c | 23 +- extracters/mtdump.txt | 22 +- extracters/ods2/access.c | 862 ++++++++++++++++++++++++++++ extracters/ods2/access.h | 237 ++++++++ extracters/ods2/access.h.bak | 237 ++++++++ extracters/ods2/build.com | 37 ++ extracters/ods2/cache.c | 411 +++++++++++++ extracters/ods2/cache.c.bak | 411 +++++++++++++ extracters/ods2/cache.h | 44 ++ extracters/ods2/descrip.h | 34 ++ extracters/ods2/device.c | 85 +++ extracters/ods2/direct.c | 550 ++++++++++++++++++ extracters/ods2/direct.h | 31 + extracters/ods2/fibdef.h | 37 ++ extracters/ods2/ods2.c | 896 +++++++++++++++++++++++++++++ extracters/ods2/ods2.c.bak | 895 +++++++++++++++++++++++++++++ extracters/ods2/phyio.h | 44 ++ extracters/ods2/phynt.c | 517 +++++++++++++++++ extracters/ods2/phyos2.c | 210 +++++++ extracters/ods2/phyvms.c | 87 +++ extracters/ods2/rms.c | 1049 ++++++++++++++++++++++++++++++++++ extracters/ods2/rms.h | 229 ++++++++ extracters/ods2/ssdef.h | 48 ++ extracters/ods2/vmstime.c | 754 ++++++++++++++++++++++++ extracters/ods2/vmstime.h | 52 ++ extracters/tpdump.c | 184 ++++++ ods2_readme.txt | 350 ++++++------ 40 files changed, 10333 insertions(+), 183 deletions(-) create mode 100644 README.md create mode 100644 converters/decsys.c create mode 100644 converters/hpconvert.c create mode 100644 converters/indent.c create mode 100644 converters/m8376.c create mode 100644 converters/mt2tpc.c create mode 100644 converters/noff.c create mode 100644 converters/strrem.c create mode 100644 converters/strsub.c create mode 100644 converters/tar2mt.c create mode 100644 converters/tar2mt.txt create mode 100644 converters/tpc2mt.c create mode 100644 crossassemblers/hpasm.c create mode 100644 extracters/ods2/access.c create mode 100644 extracters/ods2/access.h create mode 100644 extracters/ods2/access.h.bak create mode 100644 extracters/ods2/build.com create mode 100644 extracters/ods2/cache.c create mode 100644 extracters/ods2/cache.c.bak create mode 100644 extracters/ods2/cache.h create mode 100644 extracters/ods2/descrip.h create mode 100644 extracters/ods2/device.c create mode 100644 extracters/ods2/direct.c create mode 100644 extracters/ods2/direct.h create mode 100644 extracters/ods2/fibdef.h create mode 100644 extracters/ods2/ods2.c create mode 100644 extracters/ods2/ods2.c.bak create mode 100644 extracters/ods2/phyio.h create mode 100644 extracters/ods2/phynt.c create mode 100644 extracters/ods2/phyos2.c create mode 100644 extracters/ods2/phyvms.c create mode 100644 extracters/ods2/rms.c create mode 100644 extracters/ods2/rms.h create mode 100644 extracters/ods2/ssdef.h create mode 100644 extracters/ods2/vmstime.c create mode 100644 extracters/ods2/vmstime.h create mode 100644 extracters/tpdump.c diff --git a/README.md b/README.md new file mode 100644 index 0000000..d427c88 --- /dev/null +++ b/README.md @@ -0,0 +1,66 @@ +simh support/migration tools. + +ods2_readme.txt +config11 - a program for calculating the floating address space layout of a PDP-11 or VAX. +config11\config11.c +config11\config11.txt +converters - tools to convert/support simulator data files formats +converters\asc.c +converters\asc.txt +converters\dtos8cvt.c +converters\dtos8cvt.txt +converters\gt7cvt.c +converters\littcvt.c +converters\mtcvtfix.c +converters\mtcvtodd.c +converters\mtcvtv23.c +converters\mtcvtv23.txt +converters\mt2tpc.c +converters\sfmtcvt.c +converters\tar2mt.c +converters\tar2mt.txt +converters\tp512cvt.c +converters\tpc2mt.c +crossassemblers - cross assemblers for various machine architectures +crossassemblers\macro1.c +crossassemblers\macro11 +crossassemblers\macro7.c +crossassemblers\macro8x.c +crossassemblers\macro11\changes +crossassemblers\macro11\depends +crossassemblers\macro11\dumpobj.c +crossassemblers\macro11\dumpobj.dsp +crossassemblers\macro11\license +crossassemblers\macro11\macro11.c +crossassemblers\macro11\macro11.dsp +crossassemblers\macro11\macro11.dsw +crossassemblers\macro11\macro11.h +crossassemblers\macro11\makefile +crossassemblers\macro11\mlb.c +crossassemblers\macro11\mlb.h +crossassemblers\macro11\object.c +crossassemblers\macro11\object.h +crossassemblers\macro11\rad50.c +crossassemblers\macro11\rad50.h +crossassemblers\macro11\stream2.c +crossassemblers\macro11\stream2.h +crossassemblers\macro11\todo +crossassemblers\macro11\util.c +crossassemblers\macro11\util.h +extracters - data extraction tools +extracters\backup +extracters\ckabstape.c +extracters\mmdir.c +extracters\mtdump.c +extracters\mtdump.txt +extracters\rawcopy +extracters\sdsdump.c +extracters\backup\backup.c +extracters\backup\backup.h +extracters\backup\backup.txt +extracters\rawcopy\RawCopy.c +extracters\rawcopy\RawCopy.txt +putr +putr\putr.com +putr\putr.txt +putr\readme.txt diff --git a/converters/decsys.c b/converters/decsys.c new file mode 100644 index 0000000..ac12d34 --- /dev/null +++ b/converters/decsys.c @@ -0,0 +1,69 @@ +/* This program converts a decimal listing to a DECtape file + + Copyright (c) 1993-2003, Robert M. Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. +*/ + +#include +#include +#include +#include + +int main (int argc, char *argv[]) +{ +int i, j, k, word; +char *ppos, oname[256]; +int fill[256] = { 0 }; +FILE *ifile, *ofile; + +if ((argc < 2) || (argv[0] == NULL)) { + printf ("Usage is: verb file [file...]\n"); + exit (0); } + +for (i = 1; i < argc; i++) { + strcpy (oname, argv[i]); + if (ppos = strrchr (oname, '.')) strcpy (ppos, ".dtp"); + else strcat (oname, ".dtp"); + ifile = fopen (argv[i], "r"); + if (ifile == NULL) { + printf ("Error opening file: %s\n", argv[i]); + exit (0); } + ofile = fopen (oname, "wb"); + if (ofile == NULL) { + printf ("Error opening file: %s\n", oname); + exit (0); } + + printf ("Processing file %s\n", argv[i]); + fwrite (fill, sizeof (int), 256, ofile); + for (j = 0;; j++) { + k = fscanf (ifile, "%d", &word); + if (k == EOF) break; +// printf ("%06o\n", word); + fwrite (&word, sizeof (int), 1, ofile); + } + fclose (ifile); + fclose (ofile); + } + +return 0; +} diff --git a/converters/hpconvert.c b/converters/hpconvert.c new file mode 100644 index 0000000..93d8ff5 --- /dev/null +++ b/converters/hpconvert.c @@ -0,0 +1,424 @@ +/* Convert an HP disc image between SIMH and HPDrive formats. + + Copyright (c) 2012, J. David Bryan + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of the author shall not be used + in advertising or otherwise to promote the sale, use or other dealings in + this Software without prior written authorization from the author. + + + HPDrive is a free program written by Ansgar Kueckes that uses a PC and a GPIB + card to emulate a variety of vintage Hewlett-Packard disc and tape drives + that interface to computers via the HP-IB. It is available from: + + http://www.hp9845.net/9845/projects/hpdrive/ + + This program converts an HP disc image from SIMH to HPDrive format or + vice-versa. This permits interchanging images between the two programs. + + Usage: hpconvert + + SIMH writes and reads disc images in little-endian format, regardless of the + byte order of the host. In addition, SIMH accesses images for the the 7905 + and 7906 drives in platter order (i.e., all tracks on heads 0 and 1, followed + by all tracks on heads 2 and 3) to improve locality of access. It accesses + images for the 7920, 7925, and all CS/80 drives in cylinder order. + + HPDrive writes and reads images in big-endian format, regardless of the byte + order of the host, and accesses all images in cylinder order. + + This program swaps each pair of bytes in the disc image. In addition, if the + image is precisely the size of a 7905 or 7906 drive (15,151,104 or 20,201,472 + bytes, respectively), the access order is restructured from platter to + cylinder, or vice-versa. + + Note that SIMH does not currently create full-size disc images unless the + last sector on the drive is written. Therefore, it is recommended that new + images be initialized using the RTE FORMT or SWTCH programs to ensure that + the image files are of the correct size for this program and HPDrive. + + This program creates a scratch file to store the converted image. Only when + conversion is complete is the original file deleted and the scratch file + renamed to the original file's name. Running the program twice on the same + file will return the file to its original configuration. + + To decide the mode used in a 7905 or 7906 image, the program examines the OS + signature at the start of the file and compares it against a list of known + operating systems. If the OS signature is not recognized, the program + terminates without altering the file. Signature checking is not performed on + images other than those for the 7905 and 7906; those images are byte-swapped + unconditionally. + + Signatures for these operating systems and compatible 7905/06 drives are + recognized: + + - HP 1000 RTE-IVB: 7906H ICD + - HP 1000 RTE-6/VM: 7906H ICD + - HP 3000 MPE: 7905A/7906A MAC + + The signatures are contained in the first four words at the start of each + disc image. In hex representation, they are: + + - RTE-IVB ICD: 676D 06C0 776B 0B40 (LDA HHIGH ; CMA,CCE ; STA HRCNT ; ERB) + - RTE-6/VM ICD: 676D 06C0 776B 0B40 (LDA HHIGH ; CMA,CCE ; STA HRCNT ; ERB) + - MPE MAC: 5359 5354 454D 2044 ("SYSTEM D") + + These represent the start of the boot extension for RTE and the start of the + system disc label for MPE. The boot extension machine instructions are: + + RTE-IVB ICD + ----------- + + 62000 LDA EQU 062000B + 72000 STA EQU 072000B + 01200 O0 EQU HSTRT-1400B + + 02600 063555 HSTRT ABS LDA+HHIGH-O0 (word 1) + 02601 003300 CMA,CCE (word 2) + 02602 073553 ABS STA+HRCNT-O0 (word 3) + 02603 005500 ERB (word 4) + + 02753 000000 HRCNT NOP + + 02755 077377 NW#DS OCT 77377 + 02755 HHIGH EQU NW#DS + + RTE-6/VM ICD + ------------ + + 062000 LDA EQU 062000B + 072000 STA EQU 072000B + 000000R O0 EQU HSTRT-1400B + + 01400 063555 HSTRT ABS LDA+HHIGH-O0 (word 1) + 01401 003300 CMA,CCE (word 2) + 01402 073553 ABS STA+HRCNT-O0 (word 3) + 01403 005500 ERB (word 4) + + 01553 000000 HRCNT NOP + + 01555 077377 NW#DS OCT 77377 + 001555R HHIGH EQU NW#DS + + And the disc label is: + + MPE MAC and CS/80 + ----------------- + + 00000 051531 LABEL ASC 6,SYSTEM DISC (word 1) + 00001 051524 (word 2) + 00002 042515 (word 3) + 00003 020104 (word 4) + 00004 044523 + 00005 041440 + +*/ + + +#include +#include + + +/* MSVC does not provide "stdbool.h" or "unistd.h" */ + +#if defined (_MSC_VER) + typedef int bool; + const int false = 0; + #define isatty _isatty +#else + #include + #include +#endif + + +#define TRACK_SIZE ( 1 * 1 * 48 * 256) +#define CYLINDER_SIZE ( 1 * 2 * 48 * 256) +#define HP7905_SIZE (411 * 3 * 48 * 256) +#define HP7906_SIZE (411 * 4 * 48 * 256) + + +int main (int argc, + char **argv) + +{ + const char *format [] = { "HPDrive", "SIMH" }; + + const char *signatures [] = { "\x67\x6D\x06\xC0\x77\x6B\x0B\x40", /* RTE ICD */ + "SYSTEM D" }; /* MPE */ + + #define SIGNATURE_SIZE sizeof (signatures [0]) + + const int signature_count = sizeof (signatures) / SIGNATURE_SIZE; + + FILE *fin, *fout; + size_t file_size, record_size; + char *name_in, *name_out; + char sig_fwd [SIGNATURE_SIZE], sig_rev [SIGNATURE_SIZE]; + char hold, cylinder [CYLINDER_SIZE]; + bool identified = false, reversed = false, debug = false; + int i, cyl, from_cyl, to_cyl, remap; + int platter, cylinder_size, hole_size; + + +/* Read the disc image filename. */ + + if (argc != 2) { + puts ("\nHPConvert version 1.1"); + puts ("\nUsage: hpconvert "); + return 1; + } + + name_in = argv [1]; + +/* Open the source image file. */ + + fin = fopen (name_in, "rb"); + + if (!fin) { + printf ("Error: cannot open %s\n", name_in); + return 1; + } + +/* Get the size of the image. */ + + fseek (fin, 0, SEEK_END); + file_size = ftell (fin); + + +/* The blocks of a 7905 or 7906 image (as determined by the image file size) + will need to be rearranged. Set "remap" to the number of surfaces that must + be remapped. */ + + if (file_size == HP7905_SIZE) + remap = 1; + else if (file_size == HP7906_SIZE) + remap = 2; + else + remap = 0; + + +/* If the image is a 7905 or 7906, it must be remapped it for the target system. + To do that, check the OS signature to determine if it is in SIMH or HPDrive + format, and set the "reversed" flag if the signature bytes in the image are + reversed (this implies a platter-to-cylinder remapping of a 7905 or 7906 + image. */ + + if (remap) { + rewind (fin); + file_size = fread (sig_fwd, 1, SIGNATURE_SIZE, fin); + + for (i = 0; i < SIGNATURE_SIZE; i = i + 2) { + sig_rev [i] = sig_fwd [i + 1]; + sig_rev [i + 1] = sig_fwd [i]; + } + + for (i = 0; i < signature_count && identified == false; i++) { + reversed = strncmp (sig_rev, signatures [i], SIGNATURE_SIZE) == 0; + identified = reversed || strncmp (sig_fwd, signatures [i], SIGNATURE_SIZE) == 0; + } + +/* If the signature cannot be identified, then we do not know how to remap it, + so report the problem and exit. */ + + if (identified == false) { + printf ("Error: 790%i image OS signature not recognized.\n", remap + 4); + fclose (fin); + return 1; + } + } + + +/* Generate a temporary filename for the converted image. */ + + name_out = tmpnam (NULL); + + if (name_out == NULL) { + puts ("Error: cannot generate a temporary filename."); + fclose (fin); + return 1; + } + +/* Create the temporary target image. */ + + fout = fopen (name_out, "wb"); + + if (!fout) { + printf ("Error: cannot create %s\n", name_out); + fclose (fin); + return 1; + } + +/* Report the conversion that will be performed. */ + + if (remap) + printf ("Converting and remapping 790%i %s disc image to %s format.\n", + remap + 4, + format [reversed], + format [!reversed]); + else + puts ("Converting disc image."); + + +/* Enable debugging output if stdout has been redirected to a file. */ + + debug = isatty (fileno (stdout)) == 0; + + +/* Copy the source to the target image while swapping each byte pair. If the + disc image is for a 7905 or 7906, remap from platter to cylinder mode (or + vice-versa if the source image is not reversed). + + In a platter-mode image, the upper platter tracks appear in order before the + lower platter tracks. For the 7906, the cylinder-head order of the tracks is + 0-0, 0-1, 1-0, 1-1, ..., 410-0, 410-1, 0-2, 0-3, 1-2, 1-3, ..., 410-2, 410-3. + The 7905 order is the same, except that head 3 tracks are omitted. + + In a cylinder-mode image, all tracks appear in cylinder-head order, i.e., + 0-0, 0-1, 0-2, 0-3, 1-0, 1-1, ..., 410-2, 410-3, for the 7906. + + Remapping is performed in two passes, corresponding to the two platters. In + the first pass, the source tracks corresponding to the upper platter are + spread (platter-to-cylinder) or condensed (cylinder-to-platter) as they are + copied to the target file. In the second pass, the source tracks + corresponding to the lower platter are interleaved (platter-to-cylinder) or + appended (cylinder-to-platter) as they are copied to the target file. + + In either case, the bytes of each 16-bit word are swapped before copying. +*/ + + rewind (fin); + +/* If the image is not a 7905/06, simply swap each pair of bytes until EOF. */ + + if (!remap) + while (!feof (fin)) { + record_size = fread (cylinder, 1, CYLINDER_SIZE, fin); + + for (i = 0; i < record_size; i = i + 2) { + hold = cylinder [i]; + cylinder [i] = cylinder [i + 1]; + cylinder [i + 1] = hold; + } + + fwrite (cylinder, 1, record_size, fout); + } + +/* If the image is a 7905/06, remap the tracks and swap pairs of bytes. Because + we know the disc type, we know the number of platters and cylinders present + in the image. */ + + else + for (platter = 0; platter < 2; platter++) { + +/* Calculate the number of bytes per cylinder for the current platter. The + upper platter always has two tracks per cylinder. The lower platter has + either one (7905) or two (7906) tracks per cylinder. */ + + if (platter == 0) { + cylinder_size = TRACK_SIZE * 2; + hole_size = TRACK_SIZE * remap; + } + else { + cylinder_size = TRACK_SIZE * remap; + hole_size = TRACK_SIZE * 2; + } + +/* Copy a platter. */ + + for (cyl = 0; cyl < 411; cyl++) { + +/* If stdout has been redirected, output the remapping information. */ + + if (debug) { + from_cyl = ftell (fin) / TRACK_SIZE; + to_cyl = ftell (fout) / TRACK_SIZE; + + if (platter == 1 && remap == 1) + printf ("track %i => %i\n", from_cyl, to_cyl); + else + printf ("track %i, %i => %i, %i\n", + from_cyl, from_cyl + 1, to_cyl, to_cyl + 1); + } + +/* Read a cylinder from the source location. */ + + record_size = fread (cylinder, 1, cylinder_size, fin); + +/* Swap the bytes. */ + + for (i = 0; i < record_size; i = i + 2) { + hold = cylinder [i]; + cylinder [i] = cylinder [i + 1]; + cylinder [i + 1] = hold; + } + +/* Write the cylinder to the target location. */ + + fwrite (cylinder, 1, record_size, fout); + +/* For platter-to-cylinder remapping, spread the tracks by seeking ahead in the + target file; this leaves room for the lower-platter tracks in between the + upper-platter tracks. For cylinder-to-platter remapping, condense the + cylinders by seeking ahead in the source file to the next track on the + current platter. */ + + if (reversed) + fseek (fout, hole_size, SEEK_CUR); + else + fseek (fin, hole_size, SEEK_CUR); + } + + +/* End of the current platter. For platter-to-cylinder remapping, reposition + the target file to the first "hole" left for the lower-platter tracks. For + cylinder-to-platter remapping, reposition the source file to access the first + lower-platter tracks. */ + + if (reversed) + fseek (fout, cylinder_size, SEEK_SET); + else + fseek (fin, cylinder_size, SEEK_SET); + } + + +/* Close the files. */ + + fclose (fin); + fclose (fout); + + +/* Delete the original file and replace it by the reversed file. */ + + if (unlink (name_in)) { + puts ("Error: cannot replace original file, which is unchanged."); + unlink (name_out); + return 1; + } + + else if (rename (name_out, name_in)) { + printf ("Error: cannot rename temporary file %s.\n", name_out); + return 1; + } + + +/* Return success. */ + + return 0; +} diff --git a/converters/indent.c b/converters/indent.c new file mode 100644 index 0000000..03760f1 --- /dev/null +++ b/converters/indent.c @@ -0,0 +1,120 @@ +/* This program converts a SIMH source to 4-tabbing + + Copyright (c) 2005, Robert M. Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. +*/ + +#include +#include +#include +#include +#include +#include + +#define COMM_POS 56 + +int main (int argc, char *argv[]) +{ +int i, j, fill, itc, incomm, in8tab, ip, op; +char *ppos, iline[256], oline[256], oname[256]; +FILE *ifile, *ofile; + +if ((argc < 2) || (argv[0] == NULL)) { + printf ("Usage is: asc file [file...]\n"); + exit (0); } + +for (i = 1; i < argc; i++) { + strcpy (oname, argv[i]); + if (ppos = strrchr (oname, '.')) strcpy (ppos, ".new"); + else strcat (oname, ".new"); + ifile = fopen (argv[i], "ra"); + if (ifile == NULL) { + printf ("Error opening file: %s\n", argv[i]); + exit (0); } + ofile = fopen (oname, "wa"); + if (ofile == NULL) { + printf ("Error opening file: %s\n", oname); + exit (0); } + + printf ("Processing file %s\n", argv[i]); + for (incomm = in8tab = 0;;) { + for (j = 0; j < 256; j++) iline[j] = oline[j] = 0; + if (fgets (iline, 256, ifile) == NULL) break; + ip = 0; + if (!incomm) { + if (strncmp (iline, " ", 4) == 0) in8tab = 1; + else if (!isspace (iline[0]) && (iline[0] != '#') && strncmp (iline, "/*", 2)) in8tab = 0; + if ((strncmp (iline, "else {\t", 7) == 0) && + !isspace (iline[7])) { + fputs ("else {\n", ofile); + ip = 6; + } + else if ((strncmp (iline, "do {\t", 5) == 0) && + !isspace (iline[5])) { + fputs ("do {\n", ofile); + ip = 4; + } + } + for (itc = op = 0; iline[ip]; ip++) { + if (!incomm && (op == 0)) { + if (iline[ip] == '\t') { + itc++; + continue; + } + else if (itc) { + fill = (itc * 8) - (in8tab? 0: 4); + while (fill--) oline[op++] = ' '; + } + } + switch (iline[ip]) { + case '/': + if (!incomm && (iline[ip + 1] == '*')) { + incomm = 1; + if (ip != 0) { + while (op < COMM_POS) oline[op++] = ' '; + } + } + oline[op++] = iline[ip]; + break; + case '*': + if (incomm && (iline[ip + 1] == '/')) incomm = 0; + oline[op++] = iline[ip]; + break; + case '\t': + fill = 8 - (op % 8); + while (fill--) oline[op++] = ' '; + break; + case '\r': + break; + default: + oline[op++] = iline[ip]; + break; + } + } + if (op) fputs (oline, ofile); + } + fclose (ifile); + fclose (ofile); + } +return 0; +} diff --git a/converters/m8376.c b/converters/m8376.c new file mode 100644 index 0000000..48ac147 --- /dev/null +++ b/converters/m8376.c @@ -0,0 +1,71 @@ +/* This program assembles 8 PROM files into a 32bit binary file + + Copyright (c) 1993-2001, Robert M. Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. +*/ + +#include +#include +#include +#include + +static const int fnum[8] = { 60, 58, 74, 73, 90, 89, 106, 105 }; + +int main (int argc, char *argv[]) +{ +FILE *fi[8], *outf; +char fname[256]; +int c, i, j; +unsigned int wd[1024]; + +for (i = 0; i < 8; i++) { + sprintf (fname, "C:\\temp\\m8376\\m8376e%03d.bin", fnum[i]); + fi[i] = fopen (fname, "rb"); + if (fi[i] == NULL) { + printf ("Can't open file %s\n", fname); + return 0; + } + } + +for (i = 0; i < 1024; i++) { + wd[i] = 0; + for (j = 7; j >=0; j--) { + c = fgetc (fi[j]); + if (c == EOF) { + printf ("Premature end of file on file %d\n", i); + return 0; + } + wd[i] = (wd[i] << 4) | (c & 0xF); + } + } + +for (i = 0; i < 8; i++) fclose (fi[i]); +outf = fopen ("c:\\prom.bin", "wb"); +if (outf == NULL) { + printf ("Can't open output file\n"); + return 0; + } +fwrite (wd, 1024, sizeof (int), outf); +fclose (outf); +return 0; +} diff --git a/converters/mt2tpc.c b/converters/mt2tpc.c new file mode 100644 index 0000000..8bf4acf --- /dev/null +++ b/converters/mt2tpc.c @@ -0,0 +1,87 @@ +/* This program converts a simh simulated magtape to TPC format + + Copyright (c) 1993-1999, Robert M. Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. +*/ + +#include +#include +#include +#include +#define FLPSIZ 65536 +int main (int argc, char *argv[]) +{ +int i, k, fc, wc, rc; +unsigned char bc[4] = { 0 }; +unsigned char buf[FLPSIZ]; +char *progname = argv[0]; +char *ppos, oname[256]; +FILE *ifile, *ofile; + +if (argc < 2) { + fprintf (stderr, "Usage: %s file {file2 ...}\n", progname); + fprintf (stderr, "This will create a TPC tape image file named file.tpc from the input simh image file\n"); + exit (0); + } + +for (i = 1; i < argc; i++) { + strcpy (oname, argv[i]); + if (ppos = strrchr (oname, '.')) strcpy (ppos, ".tpc"); + else strcat (oname, ".tpc"); + ifile = fopen (argv[i], "rb"); + if (ifile == NULL) { + printf ("Error opening file: %s\n", argv[i]); + exit (0); } + ofile = fopen (oname, "wb"); + if (ofile == NULL) { + printf ("Error opening file: %s\n", oname); + exit (0); } + + printf ("Processing file %s\n", argv[i]); + fc = 1; rc = 0; + for (;;) { + k = fread (bc, sizeof (char), 4, ifile); + if (k == 0) break; + if (bc[2] | bc[3]) { + printf ("Invalid record size, record %d, size = 0x%02X%02X%02X%02X\n", rc, bc[3], bc[2], bc[1], bc[0]); + break; } + wc = ((unsigned int) bc[1] << 8) | (unsigned int) bc[0]; + wc = (wc + 1) & ~1; + fwrite (bc, sizeof (char), 2, ofile); + if (wc) { + k = fread (buf, sizeof (char), wc, ifile); + for ( ; k < wc; k++) buf[k] =0; + fwrite (buf, sizeof (char), wc, ofile); + k = fread (bc, sizeof (char), 4, ifile); + rc++; } + else { if (rc) printf ("End of file %d, record count = %d\n", fc, rc); + else printf ("End of tape\n"); + fc++; + rc = 0; } + } + fclose (ifile); + fclose (ofile); + } + +return 0; +} diff --git a/converters/noff.c b/converters/noff.c new file mode 100644 index 0000000..1234050 --- /dev/null +++ b/converters/noff.c @@ -0,0 +1,66 @@ +/* This program strips FF from a source listing + + Copyright (c) 2005, Robert M. Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. +*/ + +#include +#include +#include +#include +#include + +int main (int argc, char *argv[]) +{ +int i, c, ffc; +char *ppos, oline[256], oname[256]; +FILE *ifile, *ofile; + +if ((argc < 2) || (argv[0] == NULL)) { + printf ("Usage is: asc file [file...]\n"); + exit (0); } + +for (i = 1; i < argc; i++) { + strcpy (oname, argv[i]); + if (ppos = strrchr (oname, '.')) strcpy (ppos, ".new"); + else strcat (oname, ".new"); + ifile = fopen (argv[i], "ra"); + if (ifile == NULL) { + printf ("Error opening file: %s\n", argv[i]); + exit (0); } + ofile = fopen (oname, "wa"); + if (ofile == NULL) { + printf ("Error opening file: %s\n", oname); + exit (0); } + + printf ("Processing file %s\n", argv[i]); + for (ffc = 0; (c = fgetc (ifile)) != EOF; ) { + if (c == '\f') ffc++; + else fputc (c, ofile); + } + if (ffc) printf ("Form feeds removed: %d\n", ffc); + fclose (ifile); + fclose (ofile); + } +return 0; +} diff --git a/converters/strrem.c b/converters/strrem.c new file mode 100644 index 0000000..22b0996 --- /dev/null +++ b/converters/strrem.c @@ -0,0 +1,72 @@ +/* This program removes a string + + Copyright (c) 1993-2001, Robert M. Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. +*/ + +#include +#include +#include +#include + +const char *srem = "e-drive\\"; + +int main (int argc, char *argv[]) +{ +int i, slen; +char *ppos, *fpos, *tpos, oname[256], line[256]; +FILE *ifile, *ofile; + +if ((argc < 2) || (argv[0] == NULL)) { + printf ("Usage is: strrem file [file...]\n"); + exit (0); } + +slen = strlen (srem); +for (i = 1; i < argc; i++) { + strcpy (oname, argv[i]); + if (ppos = strrchr (oname, '.')) strcpy (ppos, ".new"); + else strcat (oname, ".new"); + ifile = fopen (argv[i], "r"); + if (ifile == NULL) { + printf ("Error opening file: %s\n", argv[i]); + exit (0); } + ofile = fopen (oname, "w"); + if (ofile == NULL) { + printf ("Error opening file: %s\n", oname); + exit (0); } + + printf ("Processing file %s\n", argv[i]); + while (fgets (line, 255, ifile) != NULL) { + tpos = strstr (line, srem); + if (tpos) { + fpos = tpos + slen; + while (*fpos) *tpos++ = *fpos++; + *tpos = 0; + } + fputs (line, ofile); + } + fclose (ifile); + fclose (ofile); + } +return 0; +} diff --git a/converters/strsub.c b/converters/strsub.c new file mode 100644 index 0000000..ff4503c --- /dev/null +++ b/converters/strsub.c @@ -0,0 +1,74 @@ +/* This program removes a string + + Copyright (c) 1993-2001, Robert M. Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. +*/ + +#include +#include +#include +#include + +int main (int argc, char *argv[]) +{ +int i, rmvlen; +char *ppos, *fpos, *tpos, *rmv, *ins, oname[256], line[256]; +FILE *ifile, *ofile; + +if ((argc < 4) || (argv[0] == NULL)) { + printf ("Usage is: strsub s1 s2 file [file...]\n"); + exit (0); } + +rmv = argv[1]; +rmvlen = strlen (rmv); +ins = argv[2]; +for (i = 3; i < argc; i++) { + strcpy (oname, argv[i]); + if (ppos = strrchr (oname, '.')) strcpy (ppos, ".new"); + else strcat (oname, ".new"); + ifile = fopen (argv[i], "r"); + if (ifile == NULL) { + printf ("Error opening file: %s\n", argv[i]); + exit (0); } + ofile = fopen (oname, "w"); + if (ofile == NULL) { + printf ("Error opening file: %s\n", oname); + exit (0); } + + printf ("Processing file %s\n", argv[i]); + while (fgets (line, 255, ifile) != NULL) { + tpos = strstr (line, rmv); + if (tpos) { + *tpos = 0; + fputs (line, ofile); + fputs (ins, ofile); + fpos = tpos + rmvlen; + fputs (fpos, ofile); + } + else fputs (line, ofile); + } + fclose (ifile); + fclose (ofile); + } +return 0; +} diff --git a/converters/tar2mt.c b/converters/tar2mt.c new file mode 100644 index 0000000..2edce66 --- /dev/null +++ b/converters/tar2mt.c @@ -0,0 +1,92 @@ +/* This program converts a tar file to a simulated 8192B blocked magtape + + Copyright (c) 2015, Mark Pizzolato + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + MARK PIZZOLATO BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Mark Pizzolato shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Mark Pizzolato. +*/ + +#include +#include +#include +#include + +main (int argc, char **argv) +{ +FILE *fIn = NULL, *fOut = NULL; +size_t blocksize = 8192, bytes_read; +unsigned char *br = (unsigned char *)&bytes_read; +char *progname = argv[0]; +char *buf = NULL; +char *tapname = NULL; + +if (argc < 2) { + fprintf (stderr, "Usage: %s {-b blocksize} tarfile {tarfile2 ...}\n", progname); + fprintf (stderr, "This will create a simh tap file named tarfile.tap from the input tar file\n"); + fprintf (stderr, "blocksize defaults to 8192\n"); + exit (0); + } +if ((argc >= 3) && ((strcmp("-b", argv[1])) || (strcmp("--blocksize", argv[1])))) { + if (atoi (argv[2]) <= 0) { + fprintf (stderr, "Invalid blocksize: %s\n", argv[2]); + exit (0); + } + blocksize = (size_t)atoi (argv[2]); + argc -= 2; + argv += 2; + } +while (--argc > 0) { + ++argv; + tapname = realloc (tapname, 5 + strlen (argv[0])); + if (NULL == (fIn = fopen (argv[0], "rb"))) { + fprintf (stderr, "Error Opening tar file '%s': %s\n", argv[0], strerror (errno)); + break; + } + strcpy (tapname, argv[0]); + strcat (tapname, ".tap"); + if (NULL == (fOut = fopen (tapname, "wb"))) { + fprintf (stderr, "Error Opening tap file '%s': %s\n", tapname, strerror (errno)); + break; + } + buf = realloc (buf, blocksize); + while (1) { + bytes_read = fread (buf, 1, blocksize, fIn); + if (bytes_read == 0) + break; + fputc (br[0], fOut); fputc (br[1], fOut); fputc (br[2], fOut); fputc (br[3], fOut); + fwrite (buf, 1, bytes_read, fOut); + fputc (br[0], fOut); fputc (br[1], fOut); fputc (br[2], fOut); fputc (br[3], fOut); + } + fputc (br[0], fOut); fputc (br[1], fOut); fputc (br[2], fOut); fputc (br[3], fOut); + fputc (br[0], fOut); fputc (br[1], fOut); fputc (br[2], fOut); fputc (br[3], fOut); + fclose (fIn); + fIn = NULL; + fclose (fOut); + fOut = NULL; + } +if (fIn) + fclose (fIn); +if (fOut) + fclose (fOut); +free (tapname); +free (buf); +exit(0); +} diff --git a/converters/tar2mt.txt b/converters/tar2mt.txt new file mode 100644 index 0000000..ae13dbe --- /dev/null +++ b/converters/tar2mt.txt @@ -0,0 +1,25 @@ +tar2mt converts a tar file to a simh .tap tape image. + +.tap format tape images have the format + + 4 byte record length 1 + record 1 + repeat of 4 byte record length 1 + 4 byte record length 2 + record 2 + repeat of 4 byte record length 2 + : + 4 bytes = 00000000 for end of file + +and so on. This is the tape format expected by simh, Tim Stark's TS10, +and John Wilson's E11. + +tar2mt is invoked by + + tar2mt {-b blocksize} file1 file2 file3... + +blocksize defaults to 8192. + +Each file in turn is converted from a tar file to a .tap tape image. The +input file can have any extension; the converted file will have a .tap +extension. \ No newline at end of file diff --git a/converters/tpc2mt.c b/converters/tpc2mt.c new file mode 100644 index 0000000..3c5896d --- /dev/null +++ b/converters/tpc2mt.c @@ -0,0 +1,84 @@ +/* This program converts a TPC simulated magtape to simh format + + Copyright (c) 2015, Robert M. Supnik, Mark Pizzolato + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. +*/ + +#include +#include +#include +#include +#define FLPSIZ 65536 +int main (int argc, char *argv[]) +{ +int i, k, fc, wc, rc; +unsigned char bc[4] = { 0 }; +unsigned char buf[FLPSIZ]; +char *progname = argv[0]; +char *ppos, oname[256]; +FILE *ifile, *ofile; + +if (argc < 2) { + fprintf (stderr, "Usage: %s file {file2 ...}\n", progname); + fprintf (stderr, "This will create a simh tap file named file.tap from the input tpc image file\n"); + exit (0); + } + +for (i = 1; i < argc; i++) { + strcpy (oname, argv[i]); + if (ppos = strrchr (oname, '.')) strcpy (ppos, ".tap"); + else strcat (oname, ".tap"); + ifile = fopen (argv[i], "rb"); + if (ifile == NULL) { + printf ("Error opening file: %s\n", argv[i]); + exit (0); } + ofile = fopen (oname, "wb"); + if (ofile == NULL) { + printf ("Error opening file: %s\n", oname); + exit (0); } + + printf ("Processing file %s\n", argv[i]); + fc = 1; rc = 0; + for (;;) { + k = fread (bc, sizeof (char), 2, ifile); + if (k == 0) break; + wc = ((unsigned int) bc[1] << 8) | (unsigned int) bc[0]; + wc = (wc + 1) & ~1; + fwrite (bc, sizeof (char), 4, ofile); + if (wc) { + k = fread (buf, sizeof (char), ((unsigned int) bc[1] << 8) | (unsigned int) bc[0], ifile); + for ( ; k < wc; k++) buf[k] =0; + fwrite (buf, sizeof (char), wc, ofile); + k = fwrite (bc, sizeof (char), 4, ofile); + rc++; } + else { if (rc) printf ("End of file %d, record count = %d\n", fc, rc); + else printf ("End of tape\n"); + fc++; + rc = 0; } + } + fclose (ifile); + fclose (ofile); + } + +return 0; +} diff --git a/crossassemblers/hpasm.c b/crossassemblers/hpasm.c new file mode 100644 index 0000000..69828ca --- /dev/null +++ b/crossassemblers/hpasm.c @@ -0,0 +1,930 @@ +/* +** HPASM.C -- Assembler for HP2100 +*/ +/****************************************************/ +#include +#include +#include +/****************************************************/ +#define MXSYM 1500 +#define MXLABEL 5 +#define ALLOW_SPECIALS_IN_LABEL 1 +/****************************************************/ +typedef struct { + char name[MXLABEL+1]; + long value; +} SYM; +/****************************************************/ +long nbsyms; +SYM symtab[MXSYM]; +long pass; +long addr; +char line[80]; +long lp; +long line_count; +long err_count; +long print_flag; /* =1 if current line has been printed */ +int ifn_flag=0; /* =1 if IFN does not skip */ +int ifz_flag=0; /* =1 if IFZ does not skip */ +int xif_flag=0; /* =1 if we are skipping until XIF */ +int rep_count=0; /* >0 if REP statement in process */ +/****************************************************/ +/* +** Variables for listing output routines +*/ +char listfilename[256]; +FILE *listfile; +/****************************************************/ +start_listing (nam) +/* +** Initialize listing output file +*/ +char *nam; +{ + char *ppos; + + strncpy (listfilename, nam, 250); + if (ppos = strrchr (listfilename, '.')) strcpy (ppos, ".lst"); + else strcat (listfilename, ".lst"); + listfile = fopen (listfilename, "w"); +} +/****************************************************/ +finish_listing () { +/* +** Finish off listing output file +*/ + fclose (listfile); + printf ("Listing is in %s\n", listfilename); +} +/****************************************************/ +/* +** Variables for binary output routines +*/ +char outfilename[256]; +FILE *outfile; +long outaddr; +long outcount; +long outbufsize=27; +long outbuf[27]; +/****************************************************/ +start_output (nam) +/* +** Initialize binary output file +*/ +char *nam; +{ + char *ppos; + + strncpy (outfilename, nam, 250); + if (ppos = strrchr (outfilename, '.')) strcpy (ppos, ".bin"); + else strcat (outfilename, ".bin"); + outfile = fopen (outfilename, "wb"); + outaddr = 0; + outcount = 0; +} +/****************************************************/ +send_output () { +/* +** Write block to binary output file +*/ + long ii,sum; + + fputc (outcount, outfile); + fputc (0, outfile); + fputc (outaddr >> 8, outfile); + fputc (outaddr & 255, outfile); + sum = outaddr; + for (ii=0 ; ii < outcount ; ii++) { + fputc (outbuf[ii] >> 8, outfile); + fputc (outbuf[ii] & 255, outfile); + sum += outbuf[ii]; + } + fputc (sum >> 8, outfile); + fputc (sum & 255, outfile); + outcount = 0; +} +/****************************************************/ +output_word (addr,word) +/* +** Write word to binary output file +*/ +long addr; +long word; +{ + if (outcount && (outaddr + outcount) != addr) { + send_output(); + } + if (!outcount) outaddr = addr; + outbuf[outcount++] = word; + if (outcount == outbufsize) { + send_output(); + } +} +/****************************************************/ +finish_output () { +/* +** Finish current output block, write trailing leader, +** and close output file +*/ + int ii; + if (outcount) send_output(); + for (ii=0; ii<20; ii++) fputc (0, outfile); + fclose (outfile); + printf ("Output is in %s\n", outfilename); +} +/****************************************************/ +emit (code) +long code; +{ + fprintf (listfile, " %05lo %06lo ", addr, code); + if (!print_flag) { + fprintf (listfile, "%s", line); + print_flag = 1; + } + fprintf (listfile, "\n"); + + output_word (addr, code); + addr++; +} +/****************************************************/ +err (text) +char *text; +{ + if (!print_flag) { + fprintf (listfile, " %12s %s\n", " ", line); + print_flag = 1; + } + fprintf (listfile, "ERROR: %s\n", text); + err_count++; +} +/****************************************************/ +int is_valid_label_char (ch) +char ch; +{ + if (isalpha(ch)) return (1); + if (isdigit(ch)) return (1); + if (ch=='.') return (1); +#if ALLOW_SPECIALS_IN_LABEL + if (ch=='&') return (1); + if (ch=='?') return (1); + if (ch=='#') return (1); + if (ch=='/') return (1); + if (ch=='%') return (1); + if (ch=='$') return (1); + if (ch=='[') return (1); + if (ch=='@') return (1); + if (ch=='!') return (1); + if (ch=='^') return (1); +#endif + return (0); +} +/****************************************************/ +void insert_label (label, value) +char *label; +long value; +/* +** Insert label into symbol table +*/ +{ + long i; + if (strlen(label)>MXLABEL) { + err ("Symbol name > 5"); + return; + } + for (i=0; i= 1.0) { num = num / 2; exp++; } + while (num < 0.5) { num = num * 2; exp--; } + + if (neg) num = -num; + + if (neg) num += (0177 / 65536.0 / 65536.0); + else num += (0200 / 65536.0 / 65536.0); + + if (neg && num >= -0.5) { num = num * 2; exp--; } + if (!neg && num >= 1.0) { num = num / 2; exp++; } + + if (exp < -128) return (-2); + + if (exp > 127) { + if (neg) { *a = 0x8000; *b = 0x01FE; } + else { *a = 0x7FFF; *b = 0xFFFE; } + return (-3); + } + + frac = num * 65536.0 * 128.0 * 256.0; + exp = exp << 1; + if (exp < 0) exp++; + *a = (frac >> 16) & 0xFFFF; + *b = (frac & 0xFF00) | (exp & 0x00FF); + + return (0); +} +/****************************************************/ +parse_digits (base, out) +int base; +long *out; +{ + long dig, val; + val = 0; + dig = line[lp] - '0'; + while (dig>=0 && digMXLABEL) { + err ("Illegal symbol"); + *out=0; + } else { + sym[count]=0; + find_label (sym, out); + } +} +/****************************************************/ +parse_term (out) +long *out; +{ + char ch; + ch = line[lp]; + if (isdigit(ch)) parse_const (out); + else if (is_valid_label_char(ch)) parse_sym (out); + else if (ch=='*') { lp++; *out = addr; } + else { + err ("Syntax error in expression"); + *out=0; + } +} +/****************************************************/ +parse_neg (out) +long *out; +{ + long temp; + if (line[lp]=='-') { + lp++; + parse_term (&temp); + *out = (-temp) & 0xFFFF; + } else if (line[lp]=='+') { + lp++; + parse_term (out); + } else { + parse_term (out); + } +} +/****************************************************/ +parse_sum (out) +long *out; +{ + long v1,v2,op; + parse_neg (&v1); + while (line[lp]=='+' || line[lp]=='-') { + op = line[lp++]; + parse_neg (&v2); + if (op=='+') v1 = v1 + v2; + if (op=='-') v1 = v1 - v2; + } + *out = v1 & 0xFFFF; +} +/****************************************************/ +parse_arg (out) +long *out; +{ + while (isspace (line[lp])) lp++; +/* while (line[lp]==' ') lp++; */ + parse_sum (out); +} +/****************************************************/ +parse_oct (out) +long *out; +{ + long sign,val; + + while (isspace (line[lp])) lp++; +/* while (line[lp]==' ') lp++; */ + sign = line[lp]; + if (sign=='+' || sign=='-') lp++; + parse_digits (8, &val); + if (sign=='-') val = (-val) & 0xFFFF; + *out =val; +} +/****************************************************/ +parse_dec (out, nbwords) +long *out, *nbwords; +{ + long save,sign,val,a,b; + extern double atof(); + double num; + + while (isspace (line[lp])) lp++; +/* while (line[lp]==' ') lp++; */ + save = lp; + sign = line[lp]; + if (sign=='+' || sign=='-') lp++; + parse_digits (10, &val); + if (sign=='-') val = (-val) & 0xFFFF; + out[0] = val; + *nbwords = 1; + + if (line[lp]=='.' || toupper(line[lp])=='E') { + num = atof( &(line[save]) ); + while (isdigit(line[lp]) || line[lp]=='.' || toupper(line[lp])=='E') lp++; + double_to_hp (num, &a, &b); + out[0] = a; + out[1] = b; + *nbwords = 2; + } +} +/****************************************************/ +mem_group (opcode, code) +int opcode; +long *code; +{ + long arg, out; + parse_arg (&arg); + if (arg < 02000) { + out = opcode + arg; + } else if ((arg & 0776000) == (addr & 0776000)) { + out = opcode + 02000 + (arg & 01777); + } else { + err ("Operand page error"); + out = opcode; + } + if (line[lp]==',' && toupper(line[lp+1])=='I') { + out = out + 0100000L; + lp += 2; + } + code[0] = out; +} +/****************************************************/ +io_group (opcode, code) +int opcode; +long *code; +{ + long arg, out; + parse_arg (&arg); + if (arg > 077) { + err ("Select code > 77B"); + arg = 0; + } + out = opcode + arg; + if (line[lp]==',' && toupper(line[lp+1])=='C') { + out += 001000; + lp += 2; + } + code[0] = out; +} +/****************************************************/ +overflow_group (opcode, code) +int opcode; +long *code; +{ + code[0] = opcode; + if (isspace (line[lp]) && toupper(line[lp+1])=='C') { +/* if (line[lp]==' ' && line[lp+1]=='C') { */ + code[0] += 001000; + lp += 2; + } +} +/****************************************************/ +parse_label (label) +char *label; +{ + int i=0; + while (is_valid_label_char(line[lp])) { + if (i0 && line[lp-1]=='\n') line[lp-1]=0; + print_flag = 0; + count = rep_count; + if (!count) count=1; + rep_count=0; + if (line[0]=='*') { + if (pass==2) { + fprintf (listfile, "%s\n", line); + print_flag = 1; + } + } else + while (count > 0) { + count--; + lp=0; + parse_label (label); + while (isspace (line[lp])) lp++; +/* while (line[lp]==' ') lp++; */ + if (try("IFN")) { + if (!ifn_flag) xif_flag=1; + } else if (try("IFZ")) { + if (!ifz_flag) xif_flag=1; + } else if (try("XIF")) { + xif_flag=0; + } else if (xif_flag) { + while (line[lp]) lp++; + } else if (try("ORG")) { + parse_arg (&arg); + addr = arg; + if (pass==2) { + fprintf (listfile, " %05lo %s\n", addr, line); + print_flag = 1; + if (strlen(label)) err ("Unexpected label"); + } + } else if (try("EQU")) { + parse_arg (&arg); + if (pass==1) { + if (strlen(label)) insert_label (label, arg); + } else { + fprintf (listfile, " %05lo %s\n", arg, line); + print_flag = 1; + if (!strlen(label)) err ("Label required"); + } + } else if (!isalpha(line[lp])) { + if (pass==2) err ("No instruction on line"); + } else { + + if (pass==1 && strlen(label)) insert_label (label,addr); + + if (try("HED") || try("SUP") || try("SPC") || + try("SKP") || try("UNS") || try("UNL") || + try("LST")) { + + /* Listing control ops are ignored */ + + } else if (try("END")) { + + /* No action required */ + + } else if (try("REP")) { + parse_arg (&arg); + if (arg < 1 || arg > 9999) { + err ("Illegal repeat count"); + } else { + rep_count = arg; + } + } else if (try("ABS")) { + if (pass==1) addr++; + else { + parse_arg (code); + emit (code[0]); + } + } else if (try("DEF")) { + if (pass==1) addr++; + else { + parse_arg (code); + if (line[lp]==',' && toupper(line[lp+1])=='I') { + code[0] |= 0x8000; + lp += 2; + } + emit (code[0]); + } + } else if (try("DEC")) { + long nbwords; + parse_dec (code, &nbwords); + if (pass==1) addr += nbwords; + else { + if (nbwords > 0) emit (code[0]); + if (nbwords > 1) emit (code[1]); + } + } else if (try("OCT")) { + while (1) { + parse_oct (code); + if (pass==1) addr++; + else emit (code[0]); + if (line[lp]==',') lp++; + else break; + } + } else if (try("ASC")) { + long nbwords,c1,c2; + parse_arg (&nbwords); + if (pass==1) addr += nbwords; + else if (line[lp++]!=',') err ("Missing comma"); + else + while (nbwords>0) { + if (line[lp]>31) c1=line[lp++]; else c1=' '; + if (line[lp]>31) c2=line[lp++]; else c2=' '; + emit (c1*256 + c2); + nbwords--; + } + } else if (try("BSS")) { + long nbwords; + if (pass==2) { + fprintf (listfile, " %05lo %s\n", + addr, line); + print_flag = 1; + } + parse_arg (&nbwords); + addr += nbwords; + } + else if (pass==1) addr++; + else if (try_mem_group(code)) emit (code[0]); + else if (try_srg_a(code)) emit (code[0]); + else if (try_srg_b(code)) emit (code[0]); + else if (try_asg_a(code)) emit (code[0]); + else if (try_asg_b(code)) emit (code[0]); + else if (try_io_group(code)) emit (code[0]); + else if (try_overflow(code)) emit (code[0]); + else { + emit (0L); + err ("Unknown instruction"); + } + } + if (pass==2 && !end_of_line()) err ("Missing End-of-line"); + if (pass==2 && !print_flag) fprintf (listfile, " %12s %s\n", + " ", line); + } + } + } +} +/****************************************************/ +main (argc,argv) +int argc; +char *argv[]; +{ + FILE *f1; + int ii,jj; + + jj=1; + for (ii=1 ; ii < argc ; ii++) { + if (!strcmp(argv[ii],"-n")) ifn_flag=1; + else if (!strcmp(argv[ii],"-z")) ifz_flag=1; + else argv[jj++] = argv[ii]; + } + argc = jj; + + if (argc < 2) { + printf ("Usage: hpasm options filename...\n"); + return (-1); + } + + start_output (argv[1]); + start_listing (argv[1]); + + printf ("<< PASS 1 >>\n"); + nbsyms=0; + err_count=0; + pass=1; + + for (ii=1 ; ii < argc; ii++) { + f1 = fopen (argv[ii], "r"); + if (!f1) { + printf ("File '%s' not found!\n\n", argv[ii]); + } else { + line_count=0; + printf ("%s ", argv[ii]); + fflush (stdout); + asm_pass (f1); + fclose (f1); + printf ("%d lines\n", line_count); + } + } + + show_labels(); + + printf ("<< PASS 2 >>\n"); + pass=2; + + for (ii=1 ; ii < argc; ii++) { + f1 = fopen (argv[ii], "r"); + if (!f1) { + printf ("File '%s' not found!\n\n", argv[ii]); + } else { + line_count=0; + printf ("%s ", argv[ii]); + fflush (stdout); + asm_pass (f1); + printf ("%d lines\n", line_count); + fclose (f1); + } + } + + fprintf (listfile, "%ld ERRORS\n", err_count); + printf ("%ld ERRORS\n", err_count); + + finish_output(); + finish_listing(); + + return (0); +} +/****************************************************/ diff --git a/extracters/mtdump.c b/extracters/mtdump.c index dcf2ad1..4c240ed 100644 --- a/extracters/mtdump.c +++ b/extracters/mtdump.c @@ -1,6 +1,6 @@ /* This program dumps the format of a simulated magtape - Copyright (c) 1993-2003, Robert M. Supnik + Copyright (c) 1993-2007, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -22,6 +22,9 @@ Except as contained in this notice, the name of Robert M Supnik shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + + 07-Mar-07 JDB Fixed precedence error in gap marker test + 30-Aug-06 JDB Added erase gap support */ #include @@ -41,7 +44,7 @@ int main (int argc, char *argv[]) int obj, i, k, fc, rc, tpos; unsigned int bc, fmt, rlntsiz; unsigned char *s, bca[4]; -int preveof; +int preveof, gapcount, gpos, gincr; FILE *ifile; #define MAXRLNT 65536 @@ -75,7 +78,7 @@ for (i = 1; i < argc; i++) { printf ("Error opening file: %s\n", argv[i]); exit (0); } printf ("Processing input file %s\n", argv[i]); - tpos = 0; rc = 1; fc = 1; preveof = 0; + tpos = 0; rc = 1; fc = 1; preveof = 0; gapcount = 0; printf ("Processing tape file %d\n", fc); for (obj = 1;;) { fseek (ifile, tpos, SEEK_SET); @@ -89,6 +92,20 @@ for (i = 1; i < argc; i++) { bc = (((unsigned int) bca[1]) << 8) | ((unsigned int) bca[0]); break; } + + if (k && ((bc == 0xFFFFFFFE) | (bc == 0xFFFEFFFF))) { + if (gapcount == 0) + gpos = tpos; + gincr = (bc == 0xFFFFFFFE ? 4 : 2); + gapcount = gapcount + gincr; + tpos = tpos + gincr; + continue; } + else if (gapcount) { + printf ("Obj %d, position %d, erase gap, length = %d (0x%X)\n", + obj, gpos, gapcount, gapcount); + obj++; + gapcount = 0; } + if ((k == 0) || (bc == 0xFFFFFFFF)) { printf ("End of physical tape\n"); break; } diff --git a/extracters/mtdump.txt b/extracters/mtdump.txt index 0df43f0..d85c74f 100644 --- a/extracters/mtdump.txt +++ b/extracters/mtdump.txt @@ -1,10 +1,10 @@ -mtdump dumps the record structure of a tape image file in SIMH, E11, or -TPC format. mtdump is invoked by +mtdump dumps the record structure of a tape image file in SIMH, E11, TPC, or +P7B format. mtdump is invoked by - mtdump {-sec} file1 file2 file3... + mtdump {-secp} file1 file2 file3... -where -s specifies SIMH format, -e E11 format, and -c TPC format. The -default is SIMH format. Output is to stdout, unless redirected. +where -s specifies SIMH format, -e E11 format, -c TPC format, and -p P7B +format. The default is SIMH format. Output is to stdout, unless redirected. SIMH format is as follows: @@ -33,6 +33,18 @@ TPC format is as follows: and so on. Records are padded to even byte length. +P7B format is confined to 7 track tapes, as follows: + + start of record + first 6b character and parity + : + last character + start of record + first 6b character and parity + +and so on. A P7B tape must have a dummy "last record" with a start of +record indicator. A tape mark is indicated by a character of 317 (start +of record, character 17, wrong parity for odd parity, reserved character +for even parity). + mmdir is a variant of mtdump that dumps the directory structure of an Interdata MMD (multimedia diagnostic) tape. The tape must be in SMIH format. diff --git a/extracters/ods2/access.c b/extracters/ods2/access.c new file mode 100644 index 0000000..eac583a --- /dev/null +++ b/extracters/ods2/access.c @@ -0,0 +1,862 @@ +/* Access.c v1.2 */ + +/* + This is part of ODS2 written by Paul Nankervis, + email address: Paulnank@au1.ibm.com + + ODS2 is distributed freely for all members of the + VMS community to use. However all derived works + must maintain comments in their source to acknowledge + the contibution of the original author. +*/ + +/* This module implements 'accessing' files on an ODS2 + disk volume. It uses its own low level interface to support + 'higher level' APIs. For example it is called by the + 'RMS' routines. I also had a module to implement + SYS$ASSIGN, SYS$QIOW, etc which called these routines, + the directory routines, physical I/O etc.... */ + +/* + Oh to have time to make mount do a bit more checking... :-( +*/ + +#include +#include +#include +#include +#include "ssdef.h" +#include "access.h" +#include "phyio.h" + + +#define DEBUGx on + + + + + + +/* checksum: to produce block checksum values... */ + +unsigned short checksum(unsigned short *block) +{ + register int count = 255; + register unsigned result = 0; + register unsigned short *ptr = block; + do { + result += *ptr++; + } while (--count > 0); + return result; +} + + + +/* deaccesshead: release header from INDEXF... */ + +unsigned deaccesshead(struct VIOC *vioc,struct HEAD *head,unsigned modmask) +{ +#ifdef DEBUG + printf("Deaccessing header %x\n",vioc->cache.keyval); +#endif + if (modmask) head->fh2$w_checksum = checksum((u_word *) head); + return deaccesschunk(vioc,modmask,1); +} + + +/* accesshead: find file or extension header from INDEXF... */ + +unsigned accesshead(struct VCB *vcb,struct fiddef *fid, + struct VIOC **vioc,struct HEAD **headbuff, + unsigned *modmask,unsigned wrtflg) +{ + register unsigned sts; + register struct VCBDEV *vcbdev; + register unsigned idxblk = fid->fid$w_num + (fid->fid$b_nmx << 16) - 1; + if (fid->fid$b_rvn > vcb->devices) return SS$_NOSUCHFILE; + if (fid->fid$b_rvn < 2) { + vcbdev = vcb->vcbdev; + } else { + vcbdev = &vcb->vcbdev[fid->fid$b_rvn - 1]; + } + if (vcbdev->dev == NULL) return SS$_NOSUCHFILE; + if (wrtflg && ((vcb->status & VCB_WRITE) == 0)) return SS$_WRITLCK; +#ifdef DEBUG + printf("Accessing header (%d,%d,%d)\n",(fid->fid$b_nmx << 16) + + fid->fid$w_num,fid->fid$w_seq,fid->fid$b_rvn); +#endif + idxblk += vcbdev->home.hm2$w_ibmapvbn + vcbdev->home.hm2$w_ibmapsize; + if (idxblk >= swapw(vcbdev->idxfcb->head->fh2$w_recattr.fat$l_efblk)) return SS$_NOSUCHFILE; + sts = accesschunk(vcbdev->idxfcb,idxblk,vioc,(char **) headbuff, + NULL,wrtflg ? 1 : 0,modmask); + if (sts & 1) { + register struct HEAD *head = *headbuff; + if (checksum((u_word *) head) != head->fh2$w_checksum) { +#ifdef DEBUG + printf("Accesshead checksum %d != %d\n",checksum((u_word *) head),head->fh2$w_checksum); +#endif + sts = SS$_NOSUCHFILE; + } else { + if (head->fh2$w_fid.fid$w_num != fid->fid$w_num || + head->fh2$w_fid.fid$b_nmx != fid->fid$b_nmx || + head->fh2$w_fid.fid$w_seq != fid->fid$w_seq || + (head->fh2$w_fid.fid$b_rvn != fid->fid$b_rvn && + head->fh2$w_fid.fid$b_rvn != 0)) { +#ifdef DEBUG + printf("Accesshead fileid doesn't match %d %d %d\n", + fid->fid$w_num,fid->fid$w_seq,fid->fid$b_rvn); +#endif + sts = SS$_NOSUCHFILE; + } else { + if (head->fh2$b_idoffset < 38 || + head->fh2$b_idoffset > head->fh2$b_mpoffset || + head->fh2$b_mpoffset > head->fh2$b_acoffset || + head->fh2$b_acoffset > head->fh2$b_rsoffset || + head->fh2$b_map_inuse > (head->fh2$b_acoffset - head->fh2$b_mpoffset)) { +#ifdef DEBUG + printf("Accesshead areas incorrect\n"); +#endif + sts = SS$_NOSUCHFILE; + } + } + } + if ((sts & 1) == 0) deaccesschunk(*vioc,0,0); + } + return sts; +} + + + + + + +unsigned getwindow(struct FCB *fcb,unsigned vbn,unsigned *phyrvn,unsigned *phyblk,unsigned *phylen); + +/* This routine has bugs and does NOT work properly yet!!!! + It may be something simple but I haven't had time to look... + So DON'T use mount/write!!! */ + +unsigned deallocfile(struct FCB *fcb) +{ + register unsigned sts = 1; + /* + First mark all file clusters as free in BITMAP.SYS + */ + register unsigned vbn = 1; + while (vbn <= fcb->hiblock) { + register unsigned sts; + unsigned rvn,mapblk,maplen; + register struct VCBDEV *vcbdev; + sts = getwindow(fcb,vbn,&rvn,&mapblk,&maplen); + if ((sts & 1) == 0) break; + if (rvn > fcb->vcb->devices) break; + if (rvn < 2) { + vcbdev = fcb->vcb->vcbdev; + } else { + vcbdev = &fcb->vcb->vcbdev[rvn - 1]; + } + if (vcbdev->dev == NULL) { + break; + } else { + unsigned *bitmap,blkcount,modmask; + struct VIOC *vioc; + register unsigned clustersz = vcbdev->home.hm2$w_cluster; + register unsigned clusterno = mapblk / clustersz; + sts = accesschunk(vcbdev->mapfcb,clusterno / 4096 + 2, + &vioc,(char **) &bitmap,&blkcount,1,&modmask); + if (sts & 1) { + register unsigned wordno = (clusterno % 4096) / (sizeof(unsigned) * 8); + register unsigned bitno = clusterno % (sizeof(unsigned) * 8); + do { + register unsigned mask = 1 << bitno; + vbn += clustersz; + maplen -= clustersz; + while (maplen > 0 && ++bitno < (sizeof(unsigned) * 8)) { + mask |= (mask << 1); + vbn += clustersz; + maplen -= clustersz; + } + bitmap[wordno++] |= mask; + bitno = 0; + } while (maplen > 0 && wordno < blkcount / (sizeof(unsigned) * 8)); + sts = deaccesschunk(vioc,modmask,1); + } + } + } + /* + Now reset file header bit map in INDEXF.SYS and + update each of the file headers... + */ + { + unsigned rvn = fcb->rvn; + unsigned modmask = fcb->modmask; + struct HEAD *head = fcb->head; + struct VIOC *headvioc = fcb->headvioc; + do { + struct fiddef extfid; + register struct VCBDEV *vcbdev; + if (rvn > fcb->vcb->devices) break; + if (rvn < 2) { + vcbdev = fcb->vcb->vcbdev; + } else { + vcbdev = &fcb->vcb->vcbdev[rvn - 1]; + } + if (vcbdev->dev == NULL) { + break; + } else { + unsigned *bitmap,viocmask; + struct VIOC *vioc; + register unsigned fileno = (head->fh2$w_fid.fid$b_nmx << 16) + + head->fh2$w_fid.fid$w_num - 1; + register unsigned idxblk = fileno / 4096 + + vcbdev->home.hm2$w_cluster * 4 + 1; + sts = accesschunk(vcbdev->idxfcb,idxblk,&vioc, + (char **) &bitmap,NULL,1,&viocmask); + if (sts & 1) { + bitmap[(fileno % 4096) / (sizeof(unsigned) * 8)] &= + ~(1 << (fileno % (sizeof(unsigned) * 8))); + sts = deaccesschunk(vioc,viocmask,1); + } else { + break; + } + } + head->fh2$w_fid.fid$w_num = 0; + head->fh2$w_fid.fid$b_rvn = 0; + head->fh2$w_fid.fid$b_nmx = 0; + head->fh2$w_checksum = 0; + memcpy(&extfid,&fcb->head->fh2$w_ext_fid,sizeof(struct fiddef)); + sts = deaccesshead(headvioc,head,modmask); + if ((sts & 1) == 0) break; + if (extfid.fid$b_rvn == 0) { + extfid.fid$b_rvn = rvn; + } else { + rvn = extfid.fid$b_rvn; + } + if (extfid.fid$w_num != 0 || extfid.fid$b_nmx != 0) { + sts = accesshead(fcb->vcb,&extfid,&headvioc,&head,&modmask,1); + if ((sts & 1) == 0) break; + } else { + break; + } + } while (1); + if (sts & 1) { + fcb->headvioc = NULL; + cacheuntouch(&fcb->cache,0,1); + cachedelete(&fcb->cache); + } + } + return sts; +} + + + +/* deaccessfile: finish accessing a file.... */ + +unsigned deaccessfile(struct FCB *fcb) +{ +#ifdef DEBUG + printf("Deaccessing file (%x) reference %d\n",fcb->cache.keyval,fcb->cache.refcount); +#endif + if (fcb->cache.refcount == 1) { + register unsigned refcount; + refcount = cacherefcount((struct CACHE *) fcb->wcb) + + cacherefcount((struct CACHE *) fcb->vioc); + if (refcount != 0) { + printf("File reference counts non-zero %d\n",refcount); +#ifdef DEBUG + printf("File reference counts non-zero %d %d\n", + cacherefcount((struct CACHE *) fcb->wcb),cacherefcount((struct CACHE *) fcb->vioc)); +#endif + return SS$_BUGCHECK; + } + if (fcb->cache.status & CACHE_WRITE) { + if (fcb->head->fh2$l_filechar & FH2$M_MARKDEL) { + return deallocfile(fcb); + } + } + } + cacheuntouch(&fcb->cache,1,fcb->cache.status & CACHE_WRITE); + return SS$_NORMAL; +} + + +/* Object manager for FCB objects:- we point to one of our + sub-objects (vioc or wcb) in preference to letting the + cache routines get us! But we when run out of excuses + it is time to clean up the file header... :-( */ + +struct CACHE *fcbmanager(struct CACHE *cacheobj) +{ + register struct FCB *fcb = (struct FCB *) cacheobj; + if (fcb->cache.refcount == 0) { + if (fcb->vioc != NULL) { + if (fcb->vioc->cache.refcount == 0) { + cacheobj = &fcb->vioc->cache; + } else { + cacheobj = NULL; + } + } else { + if (fcb->wcb != NULL) { + if (fcb->wcb->cache.refcount == 0) { + cacheobj = &fcb->wcb->cache; + } else { + cacheobj = NULL; + } + } else { +#ifdef DEBUG + printf("Cleaning up file (%x)\n",fcb->cache.keyval); +#endif + if (fcb->headvioc != NULL) { +#ifdef DEBUG + printf("File header deaccess (%x) %x\n",fcb->cache.keyval,fcb->cache.status); +#endif + deaccesshead(fcb->headvioc,fcb->head,fcb->modmask); + fcb->headvioc = NULL; + } + } + } + } else { + cacheobj = NULL; + } + return cacheobj; +} + + +/* accessfile: open up file for access... */ + +unsigned accessfile(struct VCB * vcb,struct fiddef * fid,struct FCB **fcbadd, + unsigned wrtflg) +{ + register struct FCB *fcb; + unsigned create = sizeof(struct FCB); + register unsigned fileno = (fid->fid$b_nmx << 16) + fid->fid$w_num; +#ifdef DEBUG + printf("Accessing file (%d,%d,%d)\n",(fid->fid$b_nmx << 16) + + fid->fid$w_num,fid->fid$w_seq,fid->fid$b_rvn); +#endif + if (fileno < 1) return SS$_BADPARAM; + if (wrtflg && ((vcb->status & VCB_WRITE) == 0)) return SS$_WRITLCK; + if (fid->fid$b_rvn > 1) fileno |= ((fid->fid$b_rvn - 1) << 24); + fcb = cachesearch((void *) &vcb->fcb,fileno,0,NULL,NULL,&create); + if (fcb == NULL) return SS$_INSFMEM; + /* If not found make one... */ + if (create == 0) { + fcb->cache.status |= 0x100; /* For debugging! */ + fcb->rvn = fid->fid$b_rvn; + if (fcb->rvn == 0 && vcb->devices > 1) fcb->rvn = 1; + fcb->vcb = vcb; + fcb->wcb = NULL; + fcb->headvioc = NULL; + fcb->vioc = NULL; + fcb->cache.objmanager = fcbmanager; + } + if (wrtflg) { + if (fcb->headvioc != NULL && (fcb->cache.status & CACHE_WRITE) == 0) { + deaccesshead(fcb->headvioc,NULL,0); + fcb->headvioc = NULL; + } + fcb->cache.status |= CACHE_WRITE; + } + if (fcb->headvioc == NULL) { + register unsigned sts; + if (vcb->idxboot != NULL) { + *fcbadd = fcb; + fcb->hiblock = 32767; /* guess at indexf.sys file size */ + fcb->highwater = 0; + fcb->head = vcb->idxboot; /* Load bootup header */ + } + sts = accesshead(vcb,fid,&fcb->headvioc,&fcb->head,&fcb->modmask,wrtflg); + if (sts & 1) { + fcb->hiblock = swapw(fcb->head->fh2$w_recattr.fat$l_hiblk); + if (fcb->head->fh2$b_idoffset > 39) { + fcb->highwater = fcb->head->fh2$l_highwater; + } else { + fcb->highwater = 0; + } + } else { + fcb->cache.objmanager = NULL; + cacheuntouch(&fcb->cache,0,0); + cachefree(&fcb->cache); + return sts; + } + } + *fcbadd = fcb; + return SS$_NORMAL; +} + + +/* accesserase: delete a file... */ + +unsigned accesserase(struct VCB * vcb,struct fiddef * fid) +{ + struct FCB *fcb; + register int sts; + sts = accessfile(vcb,fid,&fcb,1); + if (sts & 1) { + if (fcb->cache.refcount == 1) { + fcb->head->fh2$l_filechar |= FH2$M_MARKDEL; + sts = deaccessfile(fcb); + } else { + sts = deaccessfile(fcb); + sts = SS$_FILELOCKED; + } + } + return sts; +} + + + + + +/* dismount: finish processing on a volume */ + +unsigned dismount(struct VCB * vcb) +{ + register unsigned sts,device; + struct VCBDEV *vcbdev; + int expectfiles = vcb->devices; + int openfiles = cacherefcount(&vcb->fcb->cache); + if (vcb->status & VCB_WRITE) expectfiles *= 2; +#ifdef DEBUG + printf("Dismounting disk %d\n",openfiles); +#endif + sts = SS$_NORMAL; + if (openfiles != expectfiles) { + sts = SS$_DEVNOTDISM; + } else { + vcbdev = vcb->vcbdev; + for (device = 0; device < vcb->devices; device++) { + if (vcbdev->dev != NULL) { + if (vcb->status & VCB_WRITE) { + sts = deaccessfile(vcbdev->mapfcb); + vcbdev->idxfcb->headvioc->cache.status |= CACHE_MODIFIED; + vcbdev->idxfcb->cache.status &= ~CACHE_WRITE; + cacheflush(); + } + cachedeltree(&vcb->fcb->cache); + sts = deaccesshead(vcbdev->idxfcb->headvioc,NULL,0); + vcbdev->idxfcb->headvioc = NULL; + sts = cacheuntouch(&vcbdev->idxfcb->cache,0,0); + cachedeltree(&vcb->fcb->cache); + } + vcbdev++; + } + while (vcb->dircache) cachedelete((struct CACHE *) vcb->dircache); +#ifdef DEBUG + printf("Post close\n"); + cachedump(); +#endif + free(vcb); + } + return sts; +} + + + +/* mount: make disk volume available for processing... */ + +unsigned mount(unsigned flags,unsigned devices,char *devnam[],char *label[],struct VCB **retvcb) +{ + register unsigned device,sts; + struct VCB *vcb; + struct VCBDEV *vcbdev; + if (sizeof(struct HOME) != 512 || sizeof(struct HEAD) != 512) return SS$_NOTINSTALL; + vcb = (struct VCB *) malloc(sizeof(struct VCB) + (devices - 1) * sizeof(struct VCBDEV)); + if (vcb == NULL) return SS$_INSFMEM; + vcb->status = 0; + if (flags & 1) vcb->status |= VCB_WRITE; + vcb->fcb = NULL; + vcb->dircache = NULL; + vcbdev = vcb->vcbdev; + for (device = 0; device < devices; device++) { + sts = SS$_NOSUCHVOL; + vcbdev->dev = NULL; + if (strlen(devnam[device])) { + sts = device_lookup(strlen(devnam[device]),devnam[device],1,&vcbdev->dev); + if (sts & 1) { + int hba = 1; /* Header block address... */ + do { + if ((sts = phyio_read(vcbdev->dev->handle,hba,sizeof(struct HOME),(char *) &vcbdev->home)) & 1) { + if (memcmp(vcbdev->home.hm2$t_format,"DECFILE11B ",12) != 0) sts = SS$_BADPARAM; + } + } while ((sts & 1) == 0 && (hba += 1) < 100); + if (sts & 1) { + if (vcbdev->home.hm2$w_checksum2 != checksum((unsigned short *) &vcbdev->home)) { + sts = SS$_DATACHECK; + } else { + struct HEAD idxboot; /* Local for bootstrapping volume */ + struct fiddef idxfid = {1,1,0,0}; + idxfid.fid$b_rvn = device + 1; + if ((sts = phyio_read(vcbdev->dev->handle,vcbdev->home.hm2$l_ibmaplbn + + vcbdev->home.hm2$w_ibmapsize,sizeof(struct HEAD),(char *) &idxboot)) & 1) { + if (idxboot.fh2$w_fid.fid$w_num != idxfid.fid$w_num || + idxboot.fh2$w_fid.fid$b_nmx != idxfid.fid$b_nmx || + idxboot.fh2$w_fid.fid$w_seq != idxfid.fid$w_seq || + (idxboot.fh2$w_fid.fid$b_rvn != 0 && + idxboot.fh2$w_fid.fid$b_rvn != idxfid.fid$b_rvn)) + sts = SS$_DATACHECK; + if (idxboot.fh2$w_checksum != checksum((unsigned short *) &idxboot)) sts = SS$_DATACHECK; + } + vcbdev->idxfcb = NULL; + if (sts & 1) { + vcb->devices = device + 1; + vcb->idxboot = &idxboot; /* For getwindow to find index file*/ + sts = accessfile(vcb,&idxfid,&vcbdev->idxfcb,flags & 1); + vcbdev->mapfcb = NULL; + if (sts & 1) { + vcbdev->dev->vcb = vcb; + if (flags & 1) { + struct fiddef mapfid = {2,2,0,0}; + mapfid.fid$b_rvn = device + 1; + sts = accessfile(vcb,&mapfid,&vcbdev->mapfcb,1); + } + } + } + } + } + } + if ((sts & 1) == 0) vcbdev->dev = NULL; + } + if (device == 0 && vcbdev->dev == NULL) { + free(vcb); + return sts; + } + vcbdev++; + } + vcb->idxboot = NULL; + if (retvcb != NULL) *retvcb = vcb; + return sts; +} + + +/* wincmp: compare two windows routine - return -1 for less, 0 for match... */ +/* as a by product keep highest previous entry so that if a new window + is required we don't have to go right back to the initial file header */ + +int wincmp(unsigned keylen,void *key,void *node) +{ + register struct WCB *wcb = (struct WCB *) node; + if (keylen < wcb->loblk) { + return -1; + } else { + if (keylen <= wcb->hiblk) { + return 0; + } else { + register struct WCB **prev_wcb = (struct WCB **) key; + if (*prev_wcb == NULL) { + *prev_wcb = wcb; + } else { + if ((*prev_wcb)->hiblk < wcb->hiblk) *prev_wcb = wcb; + } + return 1; + } + } +} + + +/* getwindow: find a window to map VBN to LBN ... */ + +unsigned getwindow(struct FCB * fcb,unsigned vbn,unsigned *phyrvn,unsigned *phyblk,unsigned *phylen) +{ + register struct WCB *wcb; + struct WCB *prev_wcb = NULL; + unsigned create = sizeof(struct WCB); +#ifdef DEBUG + printf("Accessing window for vbn %d, file (%x)\n",vbn,fcb->cache.keyval); +#endif + wcb = cachesearch((void *) &fcb->wcb,0,vbn,&prev_wcb,wincmp,&create); + if (wcb == NULL) return SS$_INSFMEM; + /* If not found make one... */ + if (create == 0) { + register unsigned wd_base,wd_exts; + unsigned prev_hiblk,rvn; + struct VIOC *vioc; + struct HEAD *head; + wcb->cache.status |= 0x200; /* For debugging! */ + vioc = NULL; + wd_base = 1; + rvn = fcb->rvn; + head = fcb->head; + prev_hiblk = 0; + if (prev_wcb != NULL) { + register unsigned sts; + register struct fiddef *fid = &prev_wcb->hd_fid; + register struct fiddef *filefid = &fcb->head->fh2$w_fid; + if (fid->fid$w_num != filefid->fid$w_num || + fid->fid$b_nmx != filefid->fid$b_nmx || + ((fid->fid$b_rvn > 1 || fcb->rvn > 1) && fid->fid$b_rvn != fcb->rvn)) { + wd_base = prev_wcb->hd_base; + rvn = prev_wcb->hd_fid.fid$b_rvn; + sts = accesshead(fcb->vcb,fid,&vioc,&head,NULL,0); + if ((sts & 1) == 0) { + cacheuntouch(&wcb->cache,0,0); + cachefree(&wcb->cache); + return sts; + } + } + prev_hiblk = prev_wcb->hiblk; + } + wcb->hd_base = wd_base; + wd_exts = 0; +#ifdef DEBUG + printf("Making window %d %d\n",wd_base,prev_hiblk); +#endif + do { + register unsigned short *mp = (unsigned short *) head + head->fh2$b_mpoffset; + register unsigned short *me = mp + head->fh2$b_map_inuse; + while (mp < me) { + register unsigned phylen,phyblk; + switch ((*mp) >> 14) { + case 0: + phylen = 0; + mp++; + break; + case 1: + phylen = ((*mp) & 0377) + 1; + phyblk = (((*mp) & 037400) << 8) + mp[1]; + mp += 2; + break; + case 2: + phylen = ((*mp) & 037777) + 1; + phyblk = (mp[2] << 16) + mp[1]; + mp += 3; + break; + case 3: + phylen = (((*mp) & 037777) << 16) + mp[1] + 1; + phyblk = (mp[3] << 16) + mp[2]; + mp += 4; + } + if (phylen > 0 && wd_base > prev_hiblk) { + register struct EXT *ext; + if (wd_exts == 0) wcb->loblk = wd_base; + ext = &wcb->ext[wd_exts++]; + ext->phylen = phylen; + ext->phyblk = phyblk; + wd_base += phylen; + if (wd_exts >= EXTMAX) { + if (wd_base > vbn) { + break; + } else { + wd_exts = 0; + } + } + } else { + wd_base += phylen; + } + } + if (wd_base > vbn) { + break; + } else { + register unsigned sts; + struct fiddef extfid; + memcpy(&extfid,&head->fh2$w_ext_fid,sizeof(struct fiddef)); + if (extfid.fid$b_rvn != 0 && extfid.fid$b_rvn != rvn) { + wd_exts = 0;/* Can't let window extend across devices */ + rvn = extfid.fid$b_rvn; + } else { + extfid.fid$b_rvn = rvn; + } + if (vioc != NULL) deaccesshead(vioc,NULL,0); + sts = accesshead(fcb->vcb,&extfid,&vioc,&head,NULL,0); + if ((sts & 1) == 0) { + cacheuntouch(&wcb->cache,0,0); + cachefree(&wcb->cache); + return sts; + } + wcb->hd_base = wd_base; + } + } while (wd_base <= vbn); + memcpy(&wcb->hd_fid,&head->fh2$w_fid,sizeof(struct fiddef)); + wcb->hd_fid.fid$b_rvn = rvn; + wcb->hiblk = wd_base - 1; + wcb->extcount = wd_exts; + if (vioc != NULL) deaccesshead(vioc,NULL,0); + } { + register struct EXT *ext = wcb->ext; + register unsigned extcnt = wcb->extcount; + register unsigned togo = vbn - wcb->loblk; + while (togo >= ext->phylen) { + togo -= (ext++)->phylen; + if (extcnt-- < 1) return SS$_BUGCHECK; + } + *phyrvn = wcb->hd_fid.fid$b_rvn; + *phyblk = ext->phyblk + togo; + *phylen = ext->phylen - togo; +#ifdef DEBUG + printf("Mapping vbn %d to %d (%d -> %d)[%d] file (%x)\n", + vbn,*phyblk,wcb->loblk,wcb->hiblk,wcb->hd_base,fcb->cache.keyval); +#endif + cacheuntouch(&wcb->cache,1,0); + } + return SS$_NORMAL; +} + + +/* Object manager for VIOC objects:- if the object has been + modified then we need to flush it to disk before we let + the cache routines do anything to it... + This version rewrites the whole chunk - but we really should + just rewrite the blocks modified as indicated by modmask! */ + +struct CACHE *viocmanager(struct CACHE * cacheobj) +{ + register struct VIOC *vioc = (struct VIOC *) cacheobj; + if (vioc->cache.status & CACHE_MODIFIED) { + register int length = VIOC_CHUNKSIZE; + register struct FCB *fcb = vioc->fcb; + register unsigned base = vioc->cache.keyval; + register char *address = (char *) vioc->data; + printf("\nviocmanager writing vbn %d\n",base); + cachetouch(&fcb->cache); + do { + register unsigned sts; + unsigned rvn,mapblk,maplen; + register struct VCBDEV *vcbdev; + if (fcb->highwater > 0 && base >= fcb->highwater) break; + sts = getwindow(fcb,base,&rvn,&mapblk,&maplen); + if (sts & 1) { + if (maplen > (unsigned)length) maplen = length; + if (fcb->highwater > 0 && base + maplen > fcb->highwater) { + maplen = fcb->head->fh2$l_highwater - base; + } + if (rvn > fcb->vcb->devices) { + sts = SS$_NOSUCHFILE; + } else { + if (rvn < 2) { + vcbdev = fcb->vcb->vcbdev; + } else { + vcbdev = &fcb->vcb->vcbdev[rvn - 1]; + } + if (vcbdev->dev == NULL) return NULL; + sts = phyio_write(vcbdev->dev->handle,mapblk,maplen * 512,address); + } + } + if ((sts & 1) == 0) { + return NULL; + } + length -= maplen; + base += maplen; + address += maplen * 512; + } while (length > 0); + cacheuntouch(&fcb->cache,1,0); + cacheobj->status &= ~CACHE_MODIFIED; + } + return cacheobj; +} + + +/* deaccess a VIOC (chunk of a file) */ + +unsigned deaccesschunk(struct VIOC *vioc,unsigned modmask,int reuse) +{ +#ifdef DEBUG + printf("Deaccess chunk %8x\n",vioc->cache.keyval); +#endif + if ((vioc->wrtmask | modmask) == vioc->wrtmask) { + vioc->modmask |= modmask; + if (vioc->cache.refcount == 1) vioc->wrtmask = 0; + return cacheuntouch(&vioc->cache,reuse,modmask); + } else { + return SS$_WRITLCK; + } +} + + + + +/* accesschunk: return pointer to a 'chunk' of a file ... */ + +unsigned accesschunk(struct FCB *fcb,unsigned vbn,struct VIOC **retvioc, + char **retbuff,unsigned *retblocks,unsigned wrtblks, + unsigned *retmodmask) +{ + /* + First find cache entry... + */ + register struct VIOC *vioc; + unsigned create = sizeof(struct VIOC); + register unsigned base = (vbn - 1) / VIOC_CHUNKSIZE * VIOC_CHUNKSIZE + 1; +#ifdef DEBUG + printf("Access chunk %8x %d (%x)\n",base,vbn,fcb->cache.keyval); +#endif + if (wrtblks && ((fcb->cache.status & CACHE_WRITE) == 0)) return SS$_WRITLCK; + if (vbn < 1 || vbn > fcb->hiblock) return SS$_ENDOFFILE; + vioc = cachesearch((void *) &fcb->vioc,base,0,NULL,NULL,&create); + if (vioc == NULL) return SS$_INSFMEM; + /* + If not found make one... + */ + if (create == 0) { + register unsigned length; + register char *address; + register unsigned mapbase = base; + vioc->cache.status |= 0x400; /* For debugging! */ + vioc->fcb = fcb; + vioc->wrtmask = 0; + vioc->modmask = 0; + length = fcb->hiblock - mapbase + 1; + if (length > VIOC_CHUNKSIZE) length = VIOC_CHUNKSIZE; + address = (char *) vioc->data; + do { + if (fcb->highwater > 0 && mapbase >= fcb->highwater) { + memset(address,0,length * 512); + length = 0; + } else { + register unsigned sts; + unsigned rvn,mapblk,maplen; + register struct VCBDEV *vcbdev; + sts = getwindow(fcb,mapbase,&rvn,&mapblk,&maplen); + if (sts & 1) { + if (maplen > length) maplen = length; + if (fcb->highwater > 0 && mapbase + maplen > fcb->highwater) { + maplen = fcb->head->fh2$l_highwater - mapbase; + } + if (rvn > fcb->vcb->devices) { + sts = SS$_NOSUCHFILE; + } else { + if (rvn < 2) { + vcbdev = fcb->vcb->vcbdev; + } else { + vcbdev = &fcb->vcb->vcbdev[rvn - 1]; + } + if (vcbdev->dev == NULL) return SS$_NOSUCHFILE; + sts = phyio_read(vcbdev->dev->handle,mapblk,maplen * 512,address); + } + } + if ((sts & 1) == 0) { + cacheuntouch(&vioc->cache,0,0); + cachefree(&vioc->cache); + return sts; + } + length -= maplen; + mapbase += maplen; + address += maplen * 512; + } + } while (length > 0); + } + if (wrtblks) { + vioc->cache.status |= CACHE_WRITE; + vioc->cache.objmanager = viocmanager; + } + /* + Return result to caller... + */ + *retvioc = vioc; + *retbuff = vioc->data[vbn - base]; + if (wrtblks || retblocks != NULL || retmodmask != NULL) { + register unsigned modmask = 0; + register unsigned blocks = base + VIOC_CHUNKSIZE - vbn; + if (blocks > fcb->hiblock - vbn) blocks = fcb->hiblock - vbn + 1; + if (wrtblks) if (blocks > wrtblks) blocks = wrtblks; + if (retblocks != NULL) *retblocks = blocks; + if (wrtblks) { + modmask = 1 << (vbn - base); + if (blocks > 1) { + while (--blocks > 0) modmask |= modmask << 1; + } + vioc->wrtmask |= modmask; + } + if (retmodmask != NULL) *retmodmask = modmask; + } + return SS$_NORMAL; +} diff --git a/extracters/ods2/access.h b/extracters/ods2/access.h new file mode 100644 index 0000000..64af773 --- /dev/null +++ b/extracters/ods2/access.h @@ -0,0 +1,237 @@ +/* Access.h v1.2 Definitions for file access routines */ + +/* + This is part of ODS2 written by Paul Nankervis, + email address: Paulnank@au1.ibm.com + + ODS2 is distributed freely for all members of the + VMS community to use. However all derived works + must maintain comments in their source to acknowledge + the contibution of the original author. +*/ + + +#include "cache.h" +#include "vmstime.h" + +#define swapw(w) ((((unsigned int)(w[0]))<<16) | (unsigned int)(w[1])) + +#define FH2$M_NOBACKUP 0x2 +#define FH2$M_CONTIG 0x80 +#define FH2$M_DIRECTORY 0x2000 +#define FH2$M_MARKDEL 0x8000 +#define FH2$M_ERASE 0x20000 + +typedef unsigned char u_byte; +typedef unsigned short u_word; +typedef unsigned int u_long; + + +struct UIC { + u_word u_grp; + u_word u_mem; +}; + + +struct fiddef { + u_word fid$w_num; + u_word fid$w_seq; + u_byte fid$b_rvn; + u_byte fid$b_nmx; +}; + + +struct RECATTR { + u_byte fat$b_rtype; + u_byte fat$b_rattrib; + u_word fat$w_rsize; + u_word fat$l_hiblk[2]; + u_word fat$l_efblk[2]; + u_word fat$w_ffbyte; + u_byte fat$b_bktsize; + u_byte fat$b_vfcsize; + u_word fat$w_maxrec; + u_word fat$w_defext; + u_word fat$w_gbc; + u_byte fat$_UU0[8]; + u_word fat$w_versions; +}; + + +struct HOME { + u_long hm2$l_homelbn; + u_long hm2$l_alhomelbn; + u_long hm2$l_altidxlbn; + u_word hm2$w_struclev; + u_word hm2$w_cluster; + u_word hm2$w_homevbn; + u_word hm2$w_alhomevbn; + u_word hm2$w_altidxvbn; + u_word hm2$w_ibmapvbn; + u_long hm2$l_ibmaplbn; + u_long hm2$l_maxfiles; + u_word hm2$w_ibmapsize; + u_word hm2$w_resfiles; + u_word hm2$w_devtype; + u_word hm2$w_rvn; + u_word hm2$w_setcount; + u_word hm2$w_volchar; + struct UIC hm2$w_volowner; + u_long hm2$l_reserved1; + u_word hm2$w_protect; + u_word hm2$w_fileprot; + u_word hm2$w_reserved2; + u_word hm2$w_checksum1; + struct TIME hm2$q_credate; + u_byte hm2$b_window; + u_byte hm2$b_lru_lim; + u_word hm2$w_extend; + struct TIME hm2$q_retainmin; + struct TIME hm2$q_retainmax; + struct TIME hm2$q_revdate; + u_byte hm2$r_min_class[20]; + u_byte hm2$r_max_class[20]; + u_byte hm2$t_reserved3[320]; + u_long hm2$l_serialnum; + char hm2$t_strucname[12]; + char hm2$t_volname[12]; + char hm2$t_ownername[12]; + char hm2$t_format[12]; + u_word hm2$w_reserved4; + u_word hm2$w_checksum2; +}; + + +struct IDENT { + char fi2$t_filename[20]; + u_word fi2$w_revision; + struct TIME fi2$q_credate; + struct TIME fi2$q_revdate; + struct TIME fi2$q_expdate; + struct TIME fi2$q_bakdate; + char fi2$t_filenamext[66]; +}; + + +struct HEAD { + u_byte fh2$b_idoffset; + u_byte fh2$b_mpoffset; + u_byte fh2$b_acoffset; + u_byte fh2$b_rsoffset; + u_word fh2$w_seg_num; + u_word fh2$w_struclev; + struct fiddef fh2$w_fid; + struct fiddef fh2$w_ext_fid; + struct RECATTR fh2$w_recattr; + u_long fh2$l_filechar; + u_word fh2$w_reserved1; + u_byte fh2$b_map_inuse; + u_byte fh2$b_acc_mode; + struct UIC fh2$l_fileowner; + u_word fh2$w_fileprot; + struct fiddef fh2$w_backlink; + u_byte fh2$b_journal; + u_byte fh2$b_ru_active; + u_word fh2$w_reserved2; + u_long fh2$l_highwater; + u_byte fh2$b_reserved3[8]; + u_byte fh2$r_class_prot[20]; + u_byte fh2$r_restofit[402]; + u_word fh2$w_checksum; +}; + + +struct EXT { + unsigned phylen; + unsigned phyblk; +}; /* Physical extent entry */ + + +#define EXTMAX 20 + +struct WCB { + struct CACHE cache; + unsigned loblk,hiblk; /* Range of window */ + unsigned hd_base; /* File blocks prior to header */ + unsigned extcount; /* Extents in use */ + struct EXT ext[EXTMAX]; /* Mapping extents */ + struct fiddef hd_fid; /* Header info to create other WCBs */ +}; /* Window control block */ + + +#define VIOC_CHUNKSIZE 4 + +struct VIOC { + struct CACHE cache; + struct FCB *fcb; /* File this chunk is for */ + unsigned wrtmask; /* Bit mask for writable blocks */ + unsigned modmask; /* Bit mask for modified blocks */ + char data[VIOC_CHUNKSIZE][512]; /* Chunk data */ +}; /* Chunk of a file */ + + +struct FCB { + struct CACHE cache; + struct VCB *vcb; /* Volume this file is for */ + struct VIOC *headvioc; /* Index file chunk for file header */ + struct HEAD *head; /* Pointer to header block */ + struct WCB *wcb; /* Window control block tree */ + struct VIOC *vioc; /* Virtual I/O chunk tree */ + unsigned modmask; /* headvioc chunk modmask */ + unsigned hiblock; /* Highest block mapped */ + unsigned highwater; /* First high water block */ + unsigned char rvn; /* Initial file relative volume */ +}; /* File control block */ + + +struct DIRCACHE { + struct CACHE cache; + int dirlen; /* Length of directory name */ + struct fiddef dirid; /* File ID of directory */ + char dirnam[1]; /* Directory name */ +}; /* Directory cache entry */ + + +#define VCB_WRITE 1 + +struct VCB { + unsigned status; /* Volume status */ + unsigned devices; /* Number of volumes in set */ + struct HEAD *idxboot; /* Pointer to index file boot header */ + struct FCB *fcb; /* File control block tree */ + struct DIRCACHE *dircache; /* Directory cache tree */ + struct VCBDEV { + struct DEV *dev; /* Pointer to device info */ + struct FCB *idxfcb; /* Index file control block */ + struct FCB *mapfcb; /* Bitmap file control block */ + struct HOME home; /* Volume home block */ + } vcbdev[1]; /* List of volumes devices */ +}; /* Volume control block */ + + +struct DEV { + struct CACHE cache; + struct VCB *vcb; /* Pointer to volume (if mounted) */ + unsigned handle; /* Device physical I/O handle */ + unsigned status; /* Device physical status */ + unsigned sectors; /* Device physical sectors */ + unsigned sectorsize; /* Device physical sectorsize */ + int devlen; /* Length of device name */ + char devnam[1]; /* Device name */ +}; /* Device information */ + + +unsigned device_lookup(unsigned devlen,char *devnam,int create,struct DEV **retdev); + +unsigned dismount(struct VCB *vcb); +unsigned mount(unsigned flags,unsigned devices,char *devnam[],char *label[],struct VCB **vcb); + +unsigned accesserase(struct VCB *vcb,struct fiddef *fid); +unsigned deaccessfile(struct FCB *fcb); +unsigned accessfile(struct VCB *vcb,struct fiddef *fid, + struct FCB **fcb,unsigned wrtflg); + +unsigned deaccesschunk(struct VIOC *vioc,unsigned modmask,int reuse); +unsigned accesschunk(struct FCB *fcb,unsigned vbn,struct VIOC **retvioc, + char **retbuff,unsigned *retblocks,unsigned wrtblks, + unsigned *retmodmask); diff --git a/extracters/ods2/access.h.bak b/extracters/ods2/access.h.bak new file mode 100644 index 0000000..54eb28a --- /dev/null +++ b/extracters/ods2/access.h.bak @@ -0,0 +1,237 @@ +/* Access.h v1.2 Definitions for file access routines */ + +/* + This is part of ODS2 written by Paul Nankervis, + email address: Paulnank@au1.ibm.com + + ODS2 is distributed freely for all members of the + VMS community to use. However all derived works + must maintain comments in their source to acknowledge + the contibution of the original author. +*/ + + +#include "cache.h" +#include "vmstime.h" + +#define swapw(w) (w[0]<<16 | w[1]) + +#define FH2$M_NOBACKUP 0x2 +#define FH2$M_CONTIG 0x80 +#define FH2$M_DIRECTORY 0x2000 +#define FH2$M_MARKDEL 0x8000 +#define FH2$M_ERASE 0x20000 + +typedef unsigned char u_byte; +typedef unsigned short u_word; +typedef unsigned int u_long; + + +struct UIC { + u_word u_grp; + u_word u_mem; +}; + + +struct fiddef { + u_word fid$w_num; + u_word fid$w_seq; + u_byte fid$b_rvn; + u_byte fid$b_nmx; +}; + + +struct RECATTR { + u_byte fat$b_rtype; + u_byte fat$b_rattrib; + u_word fat$w_rsize; + u_word fat$l_hiblk[2]; + u_word fat$l_efblk[2]; + u_word fat$w_ffbyte; + u_byte fat$b_bktsize; + u_byte fat$b_vfcsize; + u_word fat$w_maxrec; + u_word fat$w_defext; + u_word fat$w_gbc; + u_byte fat$_UU0[8]; + u_word fat$w_versions; +}; + + +struct HOME { + u_long hm2$l_homelbn; + u_long hm2$l_alhomelbn; + u_long hm2$l_altidxlbn; + u_word hm2$w_struclev; + u_word hm2$w_cluster; + u_word hm2$w_homevbn; + u_word hm2$w_alhomevbn; + u_word hm2$w_altidxvbn; + u_word hm2$w_ibmapvbn; + u_long hm2$l_ibmaplbn; + u_long hm2$l_maxfiles; + u_word hm2$w_ibmapsize; + u_word hm2$w_resfiles; + u_word hm2$w_devtype; + u_word hm2$w_rvn; + u_word hm2$w_setcount; + u_word hm2$w_volchar; + struct UIC hm2$w_volowner; + u_long hm2$l_reserved1; + u_word hm2$w_protect; + u_word hm2$w_fileprot; + u_word hm2$w_reserved2; + u_word hm2$w_checksum1; + struct TIME hm2$q_credate; + u_byte hm2$b_window; + u_byte hm2$b_lru_lim; + u_word hm2$w_extend; + struct TIME hm2$q_retainmin; + struct TIME hm2$q_retainmax; + struct TIME hm2$q_revdate; + u_byte hm2$r_min_class[20]; + u_byte hm2$r_max_class[20]; + u_byte hm2$t_reserved3[320]; + u_long hm2$l_serialnum; + char hm2$t_strucname[12]; + char hm2$t_volname[12]; + char hm2$t_ownername[12]; + char hm2$t_format[12]; + u_word hm2$w_reserved4; + u_word hm2$w_checksum2; +}; + + +struct IDENT { + char fi2$t_filename[20]; + u_word fi2$w_revision; + struct TIME fi2$q_credate; + struct TIME fi2$q_revdate; + struct TIME fi2$q_expdate; + struct TIME fi2$q_bakdate; + char fi2$t_filenamext[66]; +}; + + +struct HEAD { + u_byte fh2$b_idoffset; + u_byte fh2$b_mpoffset; + u_byte fh2$b_acoffset; + u_byte fh2$b_rsoffset; + u_word fh2$w_seg_num; + u_word fh2$w_struclev; + struct fiddef fh2$w_fid; + struct fiddef fh2$w_ext_fid; + struct RECATTR fh2$w_recattr; + u_long fh2$l_filechar; + u_word fh2$w_reserved1; + u_byte fh2$b_map_inuse; + u_byte fh2$b_acc_mode; + struct UIC fh2$l_fileowner; + u_word fh2$w_fileprot; + struct fiddef fh2$w_backlink; + u_byte fh2$b_journal; + u_byte fh2$b_ru_active; + u_word fh2$w_reserved2; + u_long fh2$l_highwater; + u_byte fh2$b_reserved3[8]; + u_byte fh2$r_class_prot[20]; + u_byte fh2$r_restofit[402]; + u_word fh2$w_checksum; +}; + + +struct EXT { + unsigned phylen; + unsigned phyblk; +}; /* Physical extent entry */ + + +#define EXTMAX 20 + +struct WCB { + struct CACHE cache; + unsigned loblk,hiblk; /* Range of window */ + unsigned hd_base; /* File blocks prior to header */ + unsigned extcount; /* Extents in use */ + struct EXT ext[EXTMAX]; /* Mapping extents */ + struct fiddef hd_fid; /* Header info to create other WCBs */ +}; /* Window control block */ + + +#define VIOC_CHUNKSIZE 4 + +struct VIOC { + struct CACHE cache; + struct FCB *fcb; /* File this chunk is for */ + unsigned wrtmask; /* Bit mask for writable blocks */ + unsigned modmask; /* Bit mask for modified blocks */ + char data[VIOC_CHUNKSIZE][512]; /* Chunk data */ +}; /* Chunk of a file */ + + +struct FCB { + struct CACHE cache; + struct VCB *vcb; /* Volume this file is for */ + struct VIOC *headvioc; /* Index file chunk for file header */ + struct HEAD *head; /* Pointer to header block */ + struct WCB *wcb; /* Window control block tree */ + struct VIOC *vioc; /* Virtual I/O chunk tree */ + unsigned modmask; /* headvioc chunk modmask */ + unsigned hiblock; /* Highest block mapped */ + unsigned highwater; /* First high water block */ + unsigned char rvn; /* Initial file relative volume */ +}; /* File control block */ + + +struct DIRCACHE { + struct CACHE cache; + int dirlen; /* Length of directory name */ + struct fiddef dirid; /* File ID of directory */ + char dirnam[1]; /* Directory name */ +}; /* Directory cache entry */ + + +#define VCB_WRITE 1 + +struct VCB { + unsigned status; /* Volume status */ + unsigned devices; /* Number of volumes in set */ + struct HEAD *idxboot; /* Pointer to index file boot header */ + struct FCB *fcb; /* File control block tree */ + struct DIRCACHE *dircache; /* Directory cache tree */ + struct VCBDEV { + struct DEV *dev; /* Pointer to device info */ + struct FCB *idxfcb; /* Index file control block */ + struct FCB *mapfcb; /* Bitmap file control block */ + struct HOME home; /* Volume home block */ + } vcbdev[1]; /* List of volumes devices */ +}; /* Volume control block */ + + +struct DEV { + struct CACHE cache; + struct VCB *vcb; /* Pointer to volume (if mounted) */ + unsigned handle; /* Device physical I/O handle */ + unsigned status; /* Device physical status */ + unsigned sectors; /* Device physical sectors */ + unsigned sectorsize; /* Device physical sectorsize */ + int devlen; /* Length of device name */ + char devnam[1]; /* Device name */ +}; /* Device information */ + + +unsigned device_lookup(unsigned devlen,char *devnam,int create,struct DEV **retdev); + +unsigned dismount(struct VCB *vcb); +unsigned mount(unsigned flags,unsigned devices,char *devnam[],char *label[],struct VCB **vcb); + +unsigned accesserase(struct VCB *vcb,struct fiddef *fid); +unsigned deaccessfile(struct FCB *fcb); +unsigned accessfile(struct VCB *vcb,struct fiddef *fid, + struct FCB **fcb,unsigned wrtflg); + +unsigned deaccesschunk(struct VIOC *vioc,unsigned modmask,int reuse); +unsigned accesschunk(struct FCB *fcb,unsigned vbn,struct VIOC **retvioc, + char **retbuff,unsigned *retblocks,unsigned wrtblks, + unsigned *retmodmask); diff --git a/extracters/ods2/build.com b/extracters/ods2/build.com new file mode 100644 index 0000000..34da25b --- /dev/null +++ b/extracters/ods2/build.com @@ -0,0 +1,37 @@ +$ gccflag := 'cc' +$ if f$extract(0,3,gccflag).nes."GCC" then gccflag="" +$ +$ if gccflag.nes."" +$ then p1="/optim=level=3/warn=all"+p1 +$ else p1="/warn=enabl=(defunct,obsolescent,questcode,uninit,unused)"+p1 +$ endif +$ +$ default=f$parse(f$environment("PROCEDURE"),,,"DEVICE","SYNTAX_ONLY")+ - + f$parse(f$environment("PROCEDURE"),,,"DIRECTORY","SYNTAX_ONLY") +$ set def 'default' +$ +$ call cc ods2 'p1' +$ call cc rms 'p1' +$ call cc direct 'p1' +$ call cc access 'p1' +$ call cc device 'p1' +$ call cc cache 'p1' +$ call cc phyvms 'p1' +$ call cc vmstime 'p1' +$ +$ write sys$error "''f$time()' Linking..." +$ if gccflag.nes."" +$ then library = ",vaxcrtl.tmp/option" +$ create vaxcrtl.tmp +sys$share:vaxcrtl/share +$ endif +$ link 'p2' ods2,rms,direct,access,device,cache,phyvms,vmstime 'library' +$ write sys$error "''f$time()' Done" +$ exit +$ +$cc: subroutine +$ if f$search(p1+".obj;").nes."" then if f$cvtime(f$file(p1+".obj;","CDT")).ges.f$cvtime(f$file(p1+".c;","CDT")) then exit +$ write sys$error "''f$time()' Compiling ''p1'..." +$ cc 'p2' 'p1' +$ exit +$ endsubroutine diff --git a/extracters/ods2/cache.c b/extracters/ods2/cache.c new file mode 100644 index 0000000..c6374e6 --- /dev/null +++ b/extracters/ods2/cache.c @@ -0,0 +1,411 @@ +/* Cache.c v1.2 Caching control routines */ + +/* + This is part of ODS2 written by Paul Nankervis, + email address: Paulnank@au1.ibm.com + + ODS2 is distributed freely for all members of the + VMS community to use. However all derived works + must maintain comments in their source to acknowledge + the contibution of the original author. +*/ + +/* Caching seems to have a big impact on performance!!! + This version based on number of objects - probably + should change it to use space occupied by objects. + Currently use vanilla binary trees - could either + use hashing or balanced trees for better performance. */ + +/* The theory is that all cachable objects share a common + cache pool. Any object with a reference count of zero + is a candidate for destruction. All cacheable objects + have a 'struct CACHE' as the first item of the object + so that cache pointers and object pointers are interchangeable. + All cache objects are also part of a binary tree so that + they can be located. There are many instances of these + binary trees: for files on a volume, for chunks (segments) + of files, etc. Also each object can have an object manager: + a routine to handle special object deletion requirements + (for example to remove all file chunks before removing a + file), or to flush objects (write modified chunks to disk). */ + + +#include +#include +#include +#include "ssdef.h" +#include "cache.h" + + +#define DEBUG on + +/* Set limits for number of unaccessed cache entries... */ + +#define CACHELIM 64 +#define CACHEGOAL 25 + +int cachesearches = 0; +int cachecreated = 0; +int cachedeleted = 0; +int cachepeak = 0; +int cachecount = 0; +int cachefreecount = 0; + +struct CACHE cachelist = {NULL,NULL,NULL,&cachelist,&cachelist,NULL,0,0,1}; + + +/* cacheshow - to print cache statistics */ + +void cacheshow(void) +{ + printf("CACHESHOW Searches: %d Created: %d Peak: %d Count: %d Free: %d\n", + cachesearches,cachecreated,cachepeak,cachecount,cachefreecount); +} + + +void cachedump(void) +{ + register struct CACHE *cacheobj = cachelist.lstcache; + printf("%8.8s %8.8s %8.8s %8.8s %8.8s %8.8s %8.8s cachelist\n","Object", + "Parent","Left","Right","Value","Status","Count"); + while (cacheobj != &cachelist) { + printf("%8p %8p %8p %8p %8x %8x %8d\n", + cacheobj,cacheobj->parent,cacheobj->left,cacheobj->right, + cacheobj->keyval,cacheobj->status,cacheobj->refcount); + cacheobj = cacheobj->lstcache; + } +} + + +/* cacheprint - debugging tool to print out a cache subtree... */ + +void cacheprint(struct CACHE *cacheobj,int level) +{ + if (cacheobj != NULL) { + int i; + cacheprint(cacheobj->left,level + 1); + for (i = 0; i < level; i++) printf(" "); + printf("%8p %8x %8x %d\n", + cacheobj,cacheobj->keyval,cacheobj->status,cacheobj->refcount); + cacheprint(cacheobj->right,level + 1); + } +} + + +/* cacherefcount - compute reference count for cache subtree... */ + +int cacherefcount(struct CACHE *cacheobj) +{ + register int refcount = 0; + if (cacheobj != NULL) { + if (cacheobj->left != NULL) refcount += cacherefcount(cacheobj->left); + if (cacheobj->right != NULL) refcount += cacherefcount(cacheobj->right); + refcount += cacheobj->refcount; + } + return refcount; +} + + +/* cachefree - blow away item from cache - allow item to select a proxy (!) + and adjust 'the tree' containing the item. */ + +int freeactive = 0; /* In case object managers re-call cachefree... :-( */ + +struct CACHE *cachefree(struct CACHE *cacheobj) +{ + if (cacheobj->refcount != 0) { + char str[100]; + printf("cachelist, object to delete still inuse?\n"); + printf("%8p %8p %8p %8p %8x %8x %8d\n", + cacheobj,cacheobj->parent,cacheobj->left,cacheobj->right, + cacheobj->keyval,cacheobj->status,cacheobj->refcount); + printf("Type RETURN: "); + fgets(str, sizeof(str)-1, stdin); + return NULL; + } else { + register struct CACHE *proxyobj; + while (cacheobj->objmanager != NULL) { + freeactive = 1; + proxyobj = (*cacheobj->objmanager) (cacheobj); + freeactive = 0; + if (proxyobj == NULL) return NULL; + if (proxyobj == cacheobj) break; + cacheobj = proxyobj; + } + if ((cacheobj->status & CACHE_MODIFIED) && cacheobj->objmanager == NULL) + printf("cachelist No manager to write modified cache\n"); + cacheobj->lstcache->nxtcache = cacheobj->nxtcache; + cacheobj->nxtcache->lstcache = cacheobj->lstcache; + if (cacheobj->parent != NULL) { /* Check if in tree... */ + if (cacheobj->left == NULL) { + if (cacheobj->right == NULL) { + *(cacheobj->parent) = NULL; + } else { + cacheobj->right->parent = cacheobj->parent; + *(cacheobj->parent) = cacheobj->right; + } + } else { + if (cacheobj->right == NULL) { + cacheobj->left->parent = cacheobj->parent; + *(cacheobj->parent) = cacheobj->left; + } else { + register struct CACHE *leftpath = cacheobj->left; + register struct CACHE *rightpath = cacheobj->right; + while (1) { + if (leftpath->right == NULL) { + leftpath->right = cacheobj->right; + cacheobj->right->parent = &leftpath->right; + cacheobj->left->parent = cacheobj->parent; + *(cacheobj->parent) = cacheobj->left; + break; + } else { + if (rightpath->left == NULL) { + rightpath->left = cacheobj->left; + cacheobj->left->parent = &rightpath->left; + cacheobj->right->parent = cacheobj->parent; + *(cacheobj->parent) = cacheobj->right; + break; + } else { + leftpath = leftpath->right; + rightpath = rightpath->left; + } + } + } + } + } + } + if (--cachecount < 0) printf("cachelist, cache current too small\n"); + cachefreecount--; + cachedeleted--; +#ifdef DEBUG + cacheobj->parent = NULL; + cacheobj->left = NULL; + cacheobj->right = NULL; + cacheobj->nxtcache = NULL; + cacheobj->lstcache = NULL; + cacheobj->objmanager = NULL; + cacheobj->keyval = 0; + cacheobj->status = 0; + cacheobj->refcount = 0; +#endif + free(cacheobj); + return cacheobj; + } +} + + +/* cachepurge - trim size of free list */ + +void cachepurge() +{ + register struct CACHE *cacheobj = cachelist.lstcache; + while (cachefreecount > CACHEGOAL && cacheobj != &cachelist) { + register struct CACHE *lastobj = cacheobj->lstcache; +#ifdef DEBUG + if (cacheobj->lstcache->nxtcache != cacheobj || + cacheobj->nxtcache->lstcache != cacheobj || + *(cacheobj->parent) != cacheobj) { + printf("CACHE pointers in bad shape! %p %p %p - %p\n", + cacheobj->lstcache->nxtcache,cacheobj,cacheobj->nxtcache->lstcache,*(cacheobj->parent)); + } +#endif + if (cacheobj->refcount == 0) { + if (cachefree(cacheobj) != lastobj) cacheobj = lastobj; + } else { + cacheobj = lastobj; + } + } +} + + + +/* cacheflush - flush modified entries in cache */ + +void cacheflush() +{ + register struct CACHE *cacheobj = cachelist.lstcache; + while (cacheobj != &cachelist) { + if (cacheobj->status & CACHE_MODIFIED) { + if (cacheobj->objmanager != NULL) { + (*cacheobj->objmanager) (cacheobj); + } else { + printf("CACHEFLUSH No manager to write modified cache\n"); + } + } + cacheobj = cacheobj->lstcache; + } +} + + +/* cachedelete - delete an object from cache */ + +struct CACHE *cachedelete(struct CACHE *cacheobj) +{ + if (cacheobj != NULL) { + register struct CACHE *cachedel; + do { + cachedel = cachefree(cacheobj); + } while (cachedel != NULL && cachedel != cacheobj); + } + return cacheobj; +} + + + +/* cachedeltree: delete cache subtree */ + +void cachedeltree(struct CACHE *cacheobj) +{ + if (cacheobj != NULL) { + if (cacheobj->left != NULL) cachedeltree(cacheobj->left); + if (cacheobj->right != NULL) cachedeltree(cacheobj->right); + if (cacheobj->refcount == 0) cachedelete(cacheobj); + } +} + + + + +/* cacheuntouch - decrement object reference count */ + +unsigned cacheuntouch(struct CACHE *cacheobj,unsigned reuse,unsigned modflg) +{ + if (cacheobj->refcount < 1) { + char str[100]; + printf("%8p %8p %8p %8p %8x %8x %8d\n", + cacheobj,cacheobj->parent,cacheobj->left,cacheobj->right, + cacheobj->keyval,cacheobj->status,cacheobj->refcount); + printf("CACHE untouch TOO FAR!\n"); + printf("Type RETURN: "); + fgets(str, sizeof(str), stdin); + return 64; + } else { + if (modflg) { + if ((cacheobj->status & CACHE_WRITE) == 0) return SS$_WRITLCK; + cacheobj->status |= CACHE_MODIFIED; + } + if (--cacheobj->refcount == 0) { + /* Move to new list position... */ + if (reuse == 0 && cacheobj != cachelist.lstcache) { + cacheobj->lstcache->nxtcache = cacheobj->nxtcache; + cacheobj->nxtcache->lstcache = cacheobj->lstcache; + cacheobj->nxtcache = &cachelist; + cacheobj->lstcache = cachelist.lstcache; + cachelist.lstcache->nxtcache = cacheobj; + cachelist.lstcache = cacheobj; + } + cacheobj->status &= ~CACHE_WRITE; + if (++cachefreecount > CACHELIM && freeactive == 0) cachepurge(); + } + } + return 1; +} + + +/* cachetouch - add one to reference count */ + +void cachetouch(struct CACHE *cacheobj) +{ + if (cacheobj->refcount++ < 1) { +#ifdef DEBUG + if (cacheobj->lstcache->nxtcache != cacheobj || + cacheobj->nxtcache->lstcache != cacheobj || + *(cacheobj->parent) != cacheobj) { + printf("CACHE pointers in bad shape! %p %p %p - %p\n", + cacheobj->lstcache->nxtcache,cacheobj,cacheobj->nxtcache->lstcache,*(cacheobj->parent)); + } +#endif + cachefreecount--; + } + /* Move object to head of list... */ + if (cacheobj != cachelist.nxtcache) { + cacheobj->lstcache->nxtcache = cacheobj->nxtcache; + cacheobj->nxtcache->lstcache = cacheobj->lstcache; + cacheobj->lstcache = &cachelist; + cacheobj->nxtcache = cachelist.nxtcache; + cachelist.nxtcache->lstcache = cacheobj; + cachelist.nxtcache = cacheobj; + } +} + + +/* cachesearch - to find or create cache entries... + + The grand plan here was to use a hash code as a quick key + and call a compare function for duplicates. So far no data + type actually works like this - they either have a unique binary + key, or all records rely on the compare function - sigh! + Never mind, the potential is there! :-) */ + +void *cachesearch(void **root,unsigned keyval,unsigned keylen,void *key, + int (*cmpfunc) (unsigned keylen,void *key,void *node), + unsigned *createsize) +{ + register struct CACHE *parentobj = NULL; + register struct CACHE *cacheobj,**parent = (struct CACHE **) root; + cachesearches++; + while ((cacheobj = *parent) != NULL) { + parentobj = cacheobj; + if (cacheobj->keyval == keyval) { + register int cmp = 0; + if (cmpfunc != NULL) + cmp = (*cmpfunc) (keylen,key,(void *) cacheobj); + if (cmp == 0) { + cachetouch(cacheobj); + return cacheobj; + } else { + if (cmp < 0) { + parent = &cacheobj->left; + } else { + parent = &cacheobj->right; + } + } + } else { + if (cacheobj->keyval < keyval) { + parent = &cacheobj->left; + } else { + parent = &cacheobj->right; + } + } + } + if (*createsize > sizeof(struct CACHE)) { + cacheobj = (struct CACHE *) malloc(*createsize); + if (cacheobj != NULL) { + cacheobj->parent = parent; + cacheobj->left = NULL; + cacheobj->right = NULL; + cacheobj->objmanager = NULL; + cacheobj->keyval = keyval; + cacheobj->status = 0; + cacheobj->refcount = 1; + *parent = cacheobj; + *createsize = 0; + cachecreated++; + /* Add to cache list... */ + cacheobj->lstcache = &cachelist; + cacheobj->nxtcache = cachelist.nxtcache; + cachelist.nxtcache->lstcache = cacheobj; + cachelist.nxtcache = cacheobj; + if (parentobj != NULL) { + /* Attempt to mix up the tree a little... */ + if (parentobj->left == NULL) { + *parentobj->parent = cacheobj; + cacheobj->parent = parentobj->parent; + parentobj->parent = &cacheobj->left; + cacheobj->left = parentobj; + parentobj->right = NULL; + } else { + if (parentobj->right == NULL) { + *parentobj->parent = cacheobj; + cacheobj->parent = parentobj->parent; + parentobj->parent = &cacheobj->right; + cacheobj->right = parentobj; + parentobj->left = NULL; + } + } + } + if (cachecount++ >= cachepeak) cachepeak = cachecount; + } + } + return cacheobj; +} diff --git a/extracters/ods2/cache.c.bak b/extracters/ods2/cache.c.bak new file mode 100644 index 0000000..5bfb869 --- /dev/null +++ b/extracters/ods2/cache.c.bak @@ -0,0 +1,411 @@ +/* Cache.c v1.2 Caching control routines */ + +/* + This is part of ODS2 written by Paul Nankervis, + email address: Paulnank@au1.ibm.com + + ODS2 is distributed freely for all members of the + VMS community to use. However all derived works + must maintain comments in their source to acknowledge + the contibution of the original author. +*/ + +/* Caching seems to have a big impact on performance!!! + This version based on number of objects - probably + should change it to use space occupied by objects. + Currently use vanilla binary trees - could either + use hashing or balanced trees for better performance. */ + +/* The theory is that all cachable objects share a common + cache pool. Any object with a reference count of zero + is a candidate for destruction. All cacheable objects + have a 'struct CACHE' as the first item of the object + so that cache pointers and object pointers are interchangeable. + All cache objects are also part of a binary tree so that + they can be located. There are many instances of these + binary trees: for files on a volume, for chunks (segments) + of files, etc. Also each object can have an object manager: + a routine to handle special object deletion requirements + (for example to remove all file chunks before removing a + file), or to flush objects (write modified chunks to disk). */ + + +#include +#include +#include +#include "ssdef.h" +#include "cache.h" + + +#define DEBUG on + +/* Set limits for number of unaccessed cache entries... */ + +#define CACHELIM 64 +#define CACHEGOAL 25 + +int cachesearches = 0; +int cachecreated = 0; +int cachedeleted = 0; +int cachepeak = 0; +int cachecount = 0; +int cachefreecount = 0; + +struct CACHE cachelist = {NULL,NULL,NULL,&cachelist,&cachelist,NULL,0,0,1}; + + +/* cacheshow - to print cache statistics */ + +void cacheshow(void) +{ + printf("CACHESHOW Searches: %d Created: %d Peak: %d Count: %d Free: %d\n", + cachesearches,cachecreated,cachepeak,cachecount,cachefreecount); +} + + +void cachedump(void) +{ + register struct CACHE *cacheobj = cachelist.lstcache; + printf("%8.8s %8.8s %8.8s %8.8s %8.8s %8.8s %8.8s cachelist\n","Object", + "Parent","Left","Right","Value","Status","Count"); + while (cacheobj != &cachelist) { + printf("%8p %8p %8p %8p %8x %8x %8d\n", + cacheobj,cacheobj->parent,cacheobj->left,cacheobj->right, + cacheobj->keyval,cacheobj->status,cacheobj->refcount); + cacheobj = cacheobj->lstcache; + } +} + + +/* cacheprint - debugging tool to print out a cache subtree... */ + +void cacheprint(struct CACHE *cacheobj,int level) +{ + if (cacheobj != NULL) { + int i; + cacheprint(cacheobj->left,level + 1); + for (i = 0; i < level; i++) printf(" "); + printf("%8x %8x %8x %d\n", + cacheobj,cacheobj->keyval,cacheobj->status,cacheobj->refcount); + cacheprint(cacheobj->right,level + 1); + } +} + + +/* cacherefcount - compute reference count for cache subtree... */ + +int cacherefcount(struct CACHE *cacheobj) +{ + register int refcount = 0; + if (cacheobj != NULL) { + if (cacheobj->left != NULL) refcount += cacherefcount(cacheobj->left); + if (cacheobj->right != NULL) refcount += cacherefcount(cacheobj->right); + refcount += cacheobj->refcount; + } + return refcount; +} + + +/* cachefree - blow away item from cache - allow item to select a proxy (!) + and adjust 'the tree' containing the item. */ + +int freeactive = 0; /* In case object managers re-call cachefree... :-( */ + +struct CACHE *cachefree(struct CACHE *cacheobj) +{ + if (cacheobj->refcount != 0) { + char str[100]; + printf("cachelist, object to delete still inuse?\n"); + printf("%8p %8p %8p %8p %8x %8x %8d\n", + cacheobj,cacheobj->parent,cacheobj->left,cacheobj->right, + cacheobj->keyval,cacheobj->status,cacheobj->refcount); + printf("Type RETURN: "); + fgets(str, sizeof(str)-1, stdin); + return NULL; + } else { + register struct CACHE *proxyobj; + while (cacheobj->objmanager != NULL) { + freeactive = 1; + proxyobj = (*cacheobj->objmanager) (cacheobj); + freeactive = 0; + if (proxyobj == NULL) return NULL; + if (proxyobj == cacheobj) break; + cacheobj = proxyobj; + } + if ((cacheobj->status & CACHE_MODIFIED) && cacheobj->objmanager == NULL) + printf("cachelist No manager to write modified cache\n"); + cacheobj->lstcache->nxtcache = cacheobj->nxtcache; + cacheobj->nxtcache->lstcache = cacheobj->lstcache; + if (cacheobj->parent != NULL) { /* Check if in tree... */ + if (cacheobj->left == NULL) { + if (cacheobj->right == NULL) { + *(cacheobj->parent) = NULL; + } else { + cacheobj->right->parent = cacheobj->parent; + *(cacheobj->parent) = cacheobj->right; + } + } else { + if (cacheobj->right == NULL) { + cacheobj->left->parent = cacheobj->parent; + *(cacheobj->parent) = cacheobj->left; + } else { + register struct CACHE *leftpath = cacheobj->left; + register struct CACHE *rightpath = cacheobj->right; + while (1) { + if (leftpath->right == NULL) { + leftpath->right = cacheobj->right; + cacheobj->right->parent = &leftpath->right; + cacheobj->left->parent = cacheobj->parent; + *(cacheobj->parent) = cacheobj->left; + break; + } else { + if (rightpath->left == NULL) { + rightpath->left = cacheobj->left; + cacheobj->left->parent = &rightpath->left; + cacheobj->right->parent = cacheobj->parent; + *(cacheobj->parent) = cacheobj->right; + break; + } else { + leftpath = leftpath->right; + rightpath = rightpath->left; + } + } + } + } + } + } + if (--cachecount < 0) printf("cachelist, cache current too small\n"); + cachefreecount--; + cachedeleted--; +#ifdef DEBUG + cacheobj->parent = NULL; + cacheobj->left = NULL; + cacheobj->right = NULL; + cacheobj->nxtcache = NULL; + cacheobj->lstcache = NULL; + cacheobj->objmanager = NULL; + cacheobj->keyval = 0; + cacheobj->status = 0; + cacheobj->refcount = 0; +#endif + free(cacheobj); + return cacheobj; + } +} + + +/* cachepurge - trim size of free list */ + +void cachepurge() +{ + register struct CACHE *cacheobj = cachelist.lstcache; + while (cachefreecount > CACHEGOAL && cacheobj != &cachelist) { + register struct CACHE *lastobj = cacheobj->lstcache; +#ifdef DEBUG + if (cacheobj->lstcache->nxtcache != cacheobj || + cacheobj->nxtcache->lstcache != cacheobj || + *(cacheobj->parent) != cacheobj) { + printf("CACHE pointers in bad shape! %p %p %p - %p\n", + cacheobj->lstcache->nxtcache,cacheobj,cacheobj->nxtcache->lstcache,*(cacheobj->parent)); + } +#endif + if (cacheobj->refcount == 0) { + if (cachefree(cacheobj) != lastobj) cacheobj = lastobj; + } else { + cacheobj = lastobj; + } + } +} + + + +/* cacheflush - flush modified entries in cache */ + +void cacheflush() +{ + register struct CACHE *cacheobj = cachelist.lstcache; + while (cacheobj != &cachelist) { + if (cacheobj->status & CACHE_MODIFIED) { + if (cacheobj->objmanager != NULL) { + (*cacheobj->objmanager) (cacheobj); + } else { + printf("CACHEFLUSH No manager to write modified cache\n"); + } + } + cacheobj = cacheobj->lstcache; + } +} + + +/* cachedelete - delete an object from cache */ + +struct CACHE *cachedelete(struct CACHE *cacheobj) +{ + if (cacheobj != NULL) { + register struct CACHE *cachedel; + do { + cachedel = cachefree(cacheobj); + } while (cachedel != NULL && cachedel != cacheobj); + } + return cacheobj; +} + + + +/* cachedeltree: delete cache subtree */ + +void cachedeltree(struct CACHE *cacheobj) +{ + if (cacheobj != NULL) { + if (cacheobj->left != NULL) cachedeltree(cacheobj->left); + if (cacheobj->right != NULL) cachedeltree(cacheobj->right); + if (cacheobj->refcount == 0) cachedelete(cacheobj); + } +} + + + + +/* cacheuntouch - decrement object reference count */ + +unsigned cacheuntouch(struct CACHE *cacheobj,unsigned reuse,unsigned modflg) +{ + if (cacheobj->refcount < 1) { + char str[100]; + printf("%8p %8p %8p %8p %8x %8x %8d\n", + cacheobj,cacheobj->parent,cacheobj->left,cacheobj->right, + cacheobj->keyval,cacheobj->status,cacheobj->refcount); + printf("CACHE untouch TOO FAR!\n"); + printf("Type RETURN: "); + fgets(str, sizeof(str), stdin); + return 64; + } else { + if (modflg) { + if ((cacheobj->status & CACHE_WRITE) == 0) return SS$_WRITLCK; + cacheobj->status |= CACHE_MODIFIED; + } + if (--cacheobj->refcount == 0) { + /* Move to new list position... */ + if (reuse == 0 && cacheobj != cachelist.lstcache) { + cacheobj->lstcache->nxtcache = cacheobj->nxtcache; + cacheobj->nxtcache->lstcache = cacheobj->lstcache; + cacheobj->nxtcache = &cachelist; + cacheobj->lstcache = cachelist.lstcache; + cachelist.lstcache->nxtcache = cacheobj; + cachelist.lstcache = cacheobj; + } + cacheobj->status &= ~CACHE_WRITE; + if (++cachefreecount > CACHELIM && freeactive == 0) cachepurge(); + } + } + return 1; +} + + +/* cachetouch - add one to reference count */ + +void cachetouch(struct CACHE *cacheobj) +{ + if (cacheobj->refcount++ < 1) { +#ifdef DEBUG + if (cacheobj->lstcache->nxtcache != cacheobj || + cacheobj->nxtcache->lstcache != cacheobj || + *(cacheobj->parent) != cacheobj) { + printf("CACHE pointers in bad shape! %p %p %p - %p\n", + cacheobj->lstcache->nxtcache,cacheobj,cacheobj->nxtcache->lstcache,*(cacheobj->parent)); + } +#endif + cachefreecount--; + } + /* Move object to head of list... */ + if (cacheobj != cachelist.nxtcache) { + cacheobj->lstcache->nxtcache = cacheobj->nxtcache; + cacheobj->nxtcache->lstcache = cacheobj->lstcache; + cacheobj->lstcache = &cachelist; + cacheobj->nxtcache = cachelist.nxtcache; + cachelist.nxtcache->lstcache = cacheobj; + cachelist.nxtcache = cacheobj; + } +} + + +/* cachesearch - to find or create cache entries... + + The grand plan here was to use a hash code as a quick key + and call a compare function for duplicates. So far no data + type actually works like this - they either have a unique binary + key, or all records rely on the compare function - sigh! + Never mind, the potential is there! :-) */ + +void *cachesearch(void **root,unsigned keyval,unsigned keylen,void *key, + int (*cmpfunc) (unsigned keylen,void *key,void *node), + unsigned *createsize) +{ + register struct CACHE *parentobj = NULL; + register struct CACHE *cacheobj,**parent = (struct CACHE **) root; + cachesearches++; + while ((cacheobj = *parent) != NULL) { + parentobj = cacheobj; + if (cacheobj->keyval == keyval) { + register int cmp = 0; + if (cmpfunc != NULL) + cmp = (*cmpfunc) (keylen,key,(void *) cacheobj); + if (cmp == 0) { + cachetouch(cacheobj); + return cacheobj; + } else { + if (cmp < 0) { + parent = &cacheobj->left; + } else { + parent = &cacheobj->right; + } + } + } else { + if (cacheobj->keyval < keyval) { + parent = &cacheobj->left; + } else { + parent = &cacheobj->right; + } + } + } + if (*createsize > sizeof(struct CACHE)) { + cacheobj = (struct CACHE *) malloc(*createsize); + if (cacheobj != NULL) { + cacheobj->parent = parent; + cacheobj->left = NULL; + cacheobj->right = NULL; + cacheobj->objmanager = NULL; + cacheobj->keyval = keyval; + cacheobj->status = 0; + cacheobj->refcount = 1; + *parent = cacheobj; + *createsize = 0; + cachecreated++; + /* Add to cache list... */ + cacheobj->lstcache = &cachelist; + cacheobj->nxtcache = cachelist.nxtcache; + cachelist.nxtcache->lstcache = cacheobj; + cachelist.nxtcache = cacheobj; + if (parentobj != NULL) { + /* Attempt to mix up the tree a little... */ + if (parentobj->left == NULL) { + *parentobj->parent = cacheobj; + cacheobj->parent = parentobj->parent; + parentobj->parent = &cacheobj->left; + cacheobj->left = parentobj; + parentobj->right = NULL; + } else { + if (parentobj->right == NULL) { + *parentobj->parent = cacheobj; + cacheobj->parent = parentobj->parent; + parentobj->parent = &cacheobj->right; + cacheobj->right = parentobj; + parentobj->left = NULL; + } + } + } + if (cachecount++ >= cachepeak) cachepeak = cachecount; + } + } + return cacheobj; +} diff --git a/extracters/ods2/cache.h b/extracters/ods2/cache.h new file mode 100644 index 0000000..39add67 --- /dev/null +++ b/extracters/ods2/cache.h @@ -0,0 +1,44 @@ +/* Cache.h v1.2 Definitions for cache routines */ + +/* + This is part of ODS2 written by Paul Nankervis, + email address: Paulnank@au1.ibm.com + + ODS2 is distributed freely for all members of the + VMS community to use. However all derived works + must maintain comments in their source to acknowledge + the contibution of the original author. +*/ + +#ifndef CACHE_WRITE + +#define CACHE_WRITE 1 +#define CACHE_MODIFIED 2 + +struct CACHE { + struct CACHE **parent; + struct CACHE *left; + struct CACHE *right; + struct CACHE *nxtcache; + struct CACHE *lstcache; + struct CACHE *(*objmanager) (struct CACHE * cacheobj); + unsigned keyval; + unsigned status; + int refcount; +}; + +void cacheshow(void); +void cachedump(void); +void cacheprint(struct CACHE *cacheobj,int level); +void cacheflush(void); +int cacherefcount(struct CACHE *cacheobj); +void cachedeltree(struct CACHE *cacheobj); +void cachetouch(struct CACHE *cacheobj); +unsigned cacheuntouch(struct CACHE *cacheobj,unsigned reuse,unsigned modflg); +struct CACHE *cachefree(struct CACHE *cacheobj); +struct CACHE *cachedelete(struct CACHE *cacheobj); +struct CACHE *cachemake(struct CACHE **parent,unsigned length); +void *cachesearch(void **root,unsigned keyval,unsigned keylen,void *key, + int (*cmpfunc) (unsigned keylen,void *key,void *node), + unsigned *createsize); +#endif diff --git a/extracters/ods2/descrip.h b/extracters/ods2/descrip.h new file mode 100644 index 0000000..eeb09b6 --- /dev/null +++ b/extracters/ods2/descrip.h @@ -0,0 +1,34 @@ +/* Descrip.h v1.2 Definitions for descriptors */ + +/* + This is part of ODS2 written by Paul Nankervis, + email address: Paulnank@au1.ibm.com + + ODS2 is distributed freely for all members of the + VMS community to use. However all derived works + must maintain comments in their source to acknowledge + the contibution of the original author. +*/ + + +#if defined(VMS) && !defined(__GNUC__) + +#include + +#else + +#ifndef DSC$K_DTYPE_T +#define DSC$K_DTYPE_T 0 +#define DSC$K_CLASS_S 0 + +struct dsc$descriptor { + unsigned short dsc$w_length; + unsigned char dsc$w_type; + unsigned char dsc$w_class; + char *dsc$a_pointer; +}; + +#define $DESCRIPTOR(string,name) struct dsc$descriptor name = {sizeof(sring)-1,0,0,string}; + +#endif +#endif diff --git a/extracters/ods2/device.c b/extracters/ods2/device.c new file mode 100644 index 0000000..6b1cc91 --- /dev/null +++ b/extracters/ods2/device.c @@ -0,0 +1,85 @@ +/* Device.c v1.2 Module to remember and find devices...*/ + +/* + This is part of ODS2 written by Paul Nankervis, + email address: Paulnank@au1.ibm.com + + ODS2 is distributed freely for all members of the + VMS community to use. However all derived works + must maintain comments in their source to acknowledge + the contibution of the original author. +*/ + +/* Should have mechanism to return actual device name... */ + +/* This module is simple enough - it just keeps track of + device names and initialization... */ + +#include +#include +#include +#include +#include "ssdef.h" +#include "access.h" +#include "phyio.h" + + +int devcmp(unsigned keylen,void *key,void *node) +{ + register struct DEV *devnode = (struct DEV *) node; + register int cmp = keylen - devnode->devlen; + if (cmp == 0) { + register unsigned len = keylen; + register char *keynam = (char *) key; + register char *devnam = devnode->devnam; + while (len-- > 0) { + cmp = toupper(*keynam++) - toupper(*devnam++); + if (cmp != 0) break; + } + } + return cmp; +} + +struct DEV *dev_root = NULL; + +unsigned device_lookup(unsigned devlen,char *devnam, + int create,struct DEV **retdev) +{ + register struct DEV *dev; + register unsigned sts,devsiz = 0; + unsigned devcreate = 0; + while (devsiz < devlen) { + if (devnam[devsiz] == ':') break; + devsiz++; + } + if (create) devcreate = sizeof(struct DEV) + devsiz + 2; + dev = (struct DEV *) cachesearch((void **) &dev_root,0,devsiz, + (void *) devnam,devcmp,&devcreate); + if (dev == NULL) { + if (create) { + sts = SS$_INSFMEM; + } else { + sts = SS$_NOSUCHDEV; + } + } else { + struct phyio_info info; + *retdev = dev; + if (create && (devcreate == 0)) { + memcpy(dev->devnam,devnam,devsiz); + memcpy(dev->devnam + devsiz,":",2); + dev->devlen = devsiz; + sts = phyio_init(devsiz + 1,dev->devnam,&dev->handle,&info); + if (sts & 1) { + dev->status = info.status; + dev->sectors = info.sectors; + dev->sectorsize = info.sectorsize; + } else { + cacheuntouch((struct CACHE *) dev,0,0); + cachefree((struct CACHE *) dev); + } + } else { + sts = 1; + } + } + return sts; +} diff --git a/extracters/ods2/direct.c b/extracters/ods2/direct.c new file mode 100644 index 0000000..888af89 --- /dev/null +++ b/extracters/ods2/direct.c @@ -0,0 +1,550 @@ +/* Direct.c v1.2 */ + +/* + This is part of ODS2 written by Paul Nankervis, + email address: Paulnank@au1.ibm.com + + ODS2 is distributed freely for all members of the + VMS community to use. However all derived works + must maintain comments in their source to acknowledge + the contibution of the original author. +*/ + +/* This module does all directory file handling - mostly + lookups of filenames in directory files... */ + +/* This version takes relative version from last seen directory record + - this is no good if there are multiple directory records for a file! */ + +#include +#include +#include +#include +#include "ssdef.h" +#include "descrip.h" +#include "fibdef.h" +#include "access.h" +#include "direct.h" + +#define DEBUGx on + + +int directlookups = 0; +int directsearches = 0; +int directdels = 0; +int directchecks = 0; +int directmatches = 0; + + +/* directshow - to print directory statistics */ + +void directshow(void) +{ + printf("DIRECTSHOW Lookups: %d Searches: %d Deletes: %d Checks: %d Matches: %d\n", + directlookups,directsearches,directdels,directchecks,directmatches); +} + + +/* namecheck - take a name specification and return name length without + the version number, an integer version number, and a wildcard flag */ + +unsigned namecheck(char *str,int len,int *retlen,int *retver,int *wildflag) +{ + int wildcard = 0; + char *spcbeg = str; + register int dots = 0; + register char *spc = spcbeg; + register char *spcend = spc + len; + directchecks++; + while (spc < spcend) { + register char ch = *spc++; + if (ch == '.') { + if ((spc - spcbeg) > 40) return SS$_BADFILENAME; + spcbeg = spc; + if (dots++ > 1) break; + } else { + if (ch == ';') { + break; + } else { + if (ch == '*' || ch == '%') { + wildcard = 1; + } else { + if (ch == '[' || ch == ']' || ch == ':' || + !isprint(ch)) return SS$_BADFILENAME; + } + } + } + } + if ((spc - spcbeg) > 40) return SS$_BADFILENAME; + *retlen = spc - str - 1; + dots = 0; + if (spc < spcend) { + register char ch = *spc; + if (ch == '*') { + if (++spc < spcend) return SS$_BADFILENAME; + dots = 32768; + wildcard = 1; + } else { + register int sign = 1; + if (ch == '-') { + spc++; + sign = -1; + } + while (spc < spcend) { + ch = *spc++; + if (!isdigit(ch)) return SS$_BADFILENAME; + dots = dots * 10 + (ch - '0'); + } + dots *= sign; + } + } + *retver = dots; + *wildflag = wildcard; +#ifdef DEBUG + printf("Namecheck %d %d %d\n",*retlen,*retver,*wildflag); +#endif + return SS$_NORMAL; +} + + + +#define MAT_LT 0 +#define MAT_EQ 1 +#define MAT_GT 2 +#define MAT_NE 3 + +/* namematch - compare a name specification with a directory entry + and determine if there is a match, too big, too small... */ + +int namematch(char *spec,int speclen,char *entry,int entrylen) +{ + int percent = 0; + register char *spc = spec,*ent = entry; + register char *spcend = spc + speclen,*entend = ent + entrylen; + directmatches++; + /* See how much matches without wildcards... */ + if (spc < spcend && ent < entend) { + register int count = speclen; + if (entrylen < count) count = entrylen; + do { + register char sch = *spc,ech = *ent; + if (sch != ech) if (toupper(sch) != toupper(ech)) + if (sch == '%') { + percent = 1; + } else { + break; + } + spc++; + ent++; + } while (--count > 0); + } +#ifdef DEBUG + printf("Namematch %3s %d %3s %d\n",spec,speclen,entry,entrylen); +#endif + /* Mismatch - return result unless wildcard... */ + if (spc >= spcend) { + if (ent >= entend) { + return MAT_EQ; + } else { + if (percent) { + return MAT_NE; + } else { + return MAT_GT; /* Entry longer than search spec */ + } + } + } else { + register int offset = 0; + if (*spc != '*') { + if (percent) return MAT_NE; + if (ent < entend) + if (toupper(*ent) > toupper(*spc)) return MAT_GT; + return MAT_LT; + } + /* See if we can find a match with wildcards */ + spc++; + if (spc < spcend) { + do { + if (spc >= spcend) { + if (ent >= entend) break; + spc -= offset; + ent -= offset - 1; + offset = 0; + } else { + register char sch = toupper(*spc); + if (sch == '*') { + offset = 0; + spc++; + if (spc >= spcend) break; + } else { + if (ent < entend) { + register char ech = toupper(*ent); + if (sch == ech || sch == '%') { + offset++; + spc++; + ent++; + } else { + spc -= offset; + ent -= offset - 1; + offset = 0; + } + } else { + return MAT_NE; + } + } + } + } while (1); + } + } + return MAT_EQ; +} + + +unsigned freesize(char *buffer) +{ + struct dir$rec *dr = (struct dir$rec *) buffer; + do { + register char *nr = (char *) dr + dr->dir$size + 2; + if (nr >= buffer + 512) break; + dr = (struct dir$rec *) nr; + } while (1); + return (char *) dr - buffer - 2; +} + +unsigned insrec(void) +{ + printf("Insert directory record\n"); + return 0; +} + +unsigned insent(struct FCB *fcb,struct VIOC *vioc,unsigned curblk, + struct dir$rec *dr,struct dir$ent *de, + char *buffer,unsigned eofblk) +{ + printf("Insert directory entry\n"); + if (freesize(buffer) >= sizeof(struct dir$ent)) { + char *ne = (char *) de + sizeof(struct dir$ent); + memcpy(de,ne,512 - (ne - buffer)); + dr->dir$size -= sizeof(struct dir$ent); + } + return 0; +} + +/* delent - delete a directory entry */ + +unsigned delent(struct FCB *fcb,struct VIOC *vioc,unsigned curblk, + struct dir$rec *dr,struct dir$ent *de, + char *buffer,unsigned modmask,unsigned eofblk) +{ + unsigned sts = 1; + unsigned ent; + directdels++; + ent = (dr->dir$size - sizeof(struct dir$rec) + - dr->dir$namecount + 3) / sizeof(struct dir$ent); + printf("DELENT ent = %d %d %d\n",ent,curblk,eofblk); + if (ent > 1) { + char *ne = (char *) de + sizeof(struct dir$ent); + memcpy(de,ne,512 - (ne - buffer)); + dr->dir$size -= sizeof(struct dir$ent); + } else { + char *nr = (char *) dr + dr->dir$size + 2; + if (eofblk == 1 || (char *) dr > buffer || + (nr <= buffer + 510 && (unsigned short) *nr < 512)) { + memcpy(dr,nr,512 - (nr - buffer)); + } else { + printf("DELENT shrinking file size %d %d\n",curblk,eofblk); + while (curblk < eofblk) { + char *nxtbuffer; + struct VIOC *nxtvioc; + unsigned nxtmodmask; + sts = accesschunk(fcb,++curblk,&nxtvioc,&nxtbuffer,NULL,1,&nxtmodmask); + if ((sts & 1) == 0) break; + memcpy(buffer,nxtbuffer,512); + sts = deaccesschunk(vioc,modmask,1); + if ((sts & 1) == 0) break; + buffer = nxtbuffer; + vioc = nxtvioc; + modmask = nxtmodmask; + } + if (sts & 1) { + fcb->head->fh2$w_recattr.fat$l_efblk[0] = eofblk >> 16; + fcb->head->fh2$w_recattr.fat$l_efblk[1] = (eofblk & 0xffff); + eofblk--; + } + } + } + { + unsigned retsts = deaccesschunk(vioc,modmask,1); + if (sts & 1) sts = retsts; + return sts; + } +} + + +/* retent - return information about a directory entry */ + +unsigned retent(struct FCB *fcb,struct VIOC *vioc,unsigned curblk, + struct dir$rec *dr,struct dir$ent *de,struct fibdef *fib, + unsigned short *reslen,struct dsc$descriptor *resdsc, + int wildcard) +{ + register int scale = 10; + register int version = de->dir$version; + register int length = dr->dir$namecount; + register char *ptr = resdsc->dsc$a_pointer; + memcpy(ptr,dr->dir$name,length); + while (version >= scale) scale *= 10; + ptr += length++; + *ptr++ = ';'; + do { + scale /= 10; + *ptr++ = version / scale + '0'; + version %= scale; + length++; + } while (scale > 1); + *reslen = length; + memcpy(&fib->fib$w_fid_num,&de->dir$fid,sizeof(struct fiddef)); + if (fib->fib$b_fid_rvn == 0) fib->fib$b_fid_rvn = fcb->rvn; + if (wildcard || (fib->fib$w_nmctl & FIB$M_WILD)) { + fib->fib$l_wcc = curblk; + } else { + fib->fib$l_wcc = 0; + } + return deaccesschunk(vioc,0,1); +} + + +/* searchent - search for a directory entry */ + +unsigned searchent(struct FCB * fcb, + struct dsc$descriptor * fibdsc,struct dsc$descriptor * filedsc, + unsigned short *reslen,struct dsc$descriptor * resdsc,unsigned eofblk,unsigned action) +{ + register unsigned sts,curblk; + struct VIOC *vioc = NULL; + unsigned modmask; + char *searchspec,*buffer; + int searchlen,version,wildcard,wcc_flag; + struct fibdef *fib = (struct fibdef *) fibdsc->dsc$a_pointer; + directlookups++; + + /* 1) Generate start block (wcc gives start point) + 2) Search for start + 3) Scan until found or too big or end */ + + curblk = fib->fib$l_wcc; + if (curblk != 0) { + searchspec = resdsc->dsc$a_pointer; + sts = namecheck(searchspec,*reslen,&searchlen,&version,&wildcard); + if (action || wildcard) return SS$_BADFILENAME; + wcc_flag = 1; + } else { + searchspec = filedsc->dsc$a_pointer; + sts = namecheck(searchspec,filedsc->dsc$w_length,&searchlen,&version,&wildcard); + if ((action && wildcard) || (action > 1 && version < 0)) return SS$_BADFILENAME; + wcc_flag = 0; + } + if ((sts & 1) == 0) return sts; + + + /* Identify starting block...*/ + + if (*searchspec == '*' || *searchspec == '%') { + curblk = 1; + } else { + register unsigned loblk = 1,hiblk = eofblk; + if (curblk < 1 || curblk > eofblk) curblk = (eofblk + 1) / 2; + while (loblk < hiblk) { + register int cmp; + register unsigned newblk; + register struct dir$rec *dr; + directsearches++; + sts = accesschunk(fcb,curblk,&vioc,&buffer,NULL,action ? 1 : 0,&modmask); + if ((sts & 1) == 0) return sts; + dr = (struct dir$rec *) buffer; + if (dr->dir$size > 510) { + cmp = MAT_GT; + } else { + cmp = namematch(searchspec,searchlen,dr->dir$name,dr->dir$namecount); + if (cmp == MAT_EQ) { + if (wildcard || version < 1 || version > 32767) { + cmp = MAT_NE; /* no match - want to find start */ + } else { + register struct dir$ent *de = + (struct dir$ent *) (dr->dir$name + ((dr->dir$namecount + 1) & ~1)); + if (de->dir$version < version) { + cmp = MAT_GT; /* too far... */ + } else { + if (de->dir$version > version) { + cmp = MAT_LT; /* further ahead... */ + } + } + } + } + } +#ifdef DEBUG + printf("Direct %6.6s %d %6.6s %d (%d<%d<%d)-> %d\n", + searchspec,searchlen,dr->dir$name,dr->dir$namecount, + loblk,curblk,hiblk,cmp); +#endif + switch (cmp) { + case MAT_LT: + if (curblk == fib->fib$l_wcc) { + newblk = hiblk = loblk = curblk; + } else { + loblk = curblk; + newblk = (loblk + hiblk + 1) / 2; + } + break; + case MAT_GT: + case MAT_NE: + newblk = (loblk + curblk) / 2; + hiblk = curblk - 1; + break; + default: + newblk = hiblk = loblk = curblk; + } + if (newblk != curblk) { + sts = deaccesschunk(vioc,0,1); + if ((sts & 1) == 0) return sts; + vioc = NULL; + curblk = newblk; + } + } + } + + + /* Now to read sequentially to find entry... */ + + while ((sts & 1) && curblk <= eofblk) { + register struct dir$rec *dr; + if (vioc == NULL) { + sts = accesschunk(fcb,curblk,&vioc,&buffer,NULL,action ? 1 : 0,&modmask); + if ((sts & 1) == 0) return sts; + } + dr = (struct dir$rec *) buffer; + do { + register int cmp; + register char *nr = (char *) dr + dr->dir$size + 2; + if (nr >= buffer + 512) break; + cmp = namematch(searchspec,searchlen,dr->dir$name,dr->dir$namecount); +#ifdef DEBUF + printf("Direct %6.6s %d %6.6s %d -> %d\n", + searchspec,searchlen,dr->dir$name,dr->dir$namecount,cmp); +#endif + if (cmp == MAT_GT) { + if (wcc_flag) { + wcc_flag = 0; + searchspec = filedsc->dsc$a_pointer; + sts = namecheck(searchspec,filedsc->dsc$w_length,&searchlen,&version,&wildcard); + if ((sts & 1) == 0) break; + } else { + curblk = eofblk; /* give up */ + break; + } + } else { + if (cmp == MAT_EQ) { + register int relver = 0; + register struct dir$ent *de = (struct dir$ent *) (dr->dir$name + + ((dr->dir$namecount + 1) & ~1)); + while ((char *) de < nr) { + if (version >= de->dir$version || (version < 1 && version >= relver)) { + cmp = MAT_GT; + if (version > 32767 || version == relver || + version == de->dir$version) cmp = MAT_EQ; + if (wcc_flag) { + wcc_flag = 0; + searchspec = filedsc->dsc$a_pointer; + sts = namecheck(searchspec,filedsc->dsc$w_length,&searchlen,&version,&wildcard); + if ((sts & 1) == 0) break; + if (namematch(searchspec,searchlen,dr->dir$name, + dr->dir$namecount) != MAT_EQ) { + break; + } + if (cmp == MAT_EQ) { + cmp = MAT_LT; + } else { + cmp = MAT_LT; + if (version >= de->dir$version || (version < 1 && version >= relver)) { + cmp = MAT_GT; + if (version > 32767 || version == relver || + version == de->dir$version) cmp = MAT_EQ; + } + } + } + if (cmp == MAT_EQ) { + switch (action) { + case 0: + return +retent(fcb,vioc,curblk,dr,de,fib,reslen,resdsc,wildcard); + case 1: + return +delent(fcb,vioc,curblk,dr,de,buffer,modmask,eofblk); + default: + sts = SS$_DUPFILENAME; + de = (struct dir$ent *) nr; + } + } else { + if (cmp == MAT_GT) break; + } + } + relver--; + de++; + } + if ((sts & 1) == 0) break; + if (action == 2) { + return insent(fcb,vioc,curblk,dr,de,buffer,eofblk); + } + } + dr = (struct dir$rec *) nr; + } + } while (1); + { + register unsigned dests = deaccesschunk(vioc,0,1); + vioc = NULL; + if (sts & 1) sts = dests; + } + curblk++; + } + if (action == 2) { + return insrec(); + } + if (sts & 1) { + fib->fib$l_wcc = 0; + if (wcc_flag || wildcard) { + sts = SS$_NOMOREFILES; + } else { + sts = SS$_NOSUCHFILE; + } + } + return sts; +} + + +/* direct - this routine handles all directory manipulations:- + action 0 - find directory entry + 1 - delete entry + 2 - create an entry */ + +unsigned direct(struct VCB *vcb,struct dsc$descriptor * fibdsc, + struct dsc$descriptor *filedsc,unsigned short *reslen, + struct dsc$descriptor *resdsc,unsigned action) +{ + struct FCB *fcb; + register unsigned sts,eofblk; + register struct fibdef *fib = (struct fibdef *) fibdsc->dsc$a_pointer; + sts = accessfile(vcb,(struct fiddef *) & fib->fib$w_did_num,&fcb,action); + if (sts & 1) { + if (fcb->head->fh2$l_filechar & FH2$M_DIRECTORY) { + eofblk = swapw(fcb->head->fh2$w_recattr.fat$l_efblk); + if (fcb->head->fh2$w_recattr.fat$w_ffbyte == 0) --eofblk; + sts = searchent(fcb,fibdsc,filedsc,reslen,resdsc,eofblk,action); + } else { + sts = SS$_BADIRECTORY; + } + { + register unsigned dests = deaccessfile(fcb); + if (sts & 1) sts = dests; + } + } + return sts; +} diff --git a/extracters/ods2/direct.h b/extracters/ods2/direct.h new file mode 100644 index 0000000..17f5717 --- /dev/null +++ b/extracters/ods2/direct.h @@ -0,0 +1,31 @@ +/* Direct.h v1.2 Definitions for directory access routines */ + +/* + This is part of ODS2 written by Paul Nankervis, + email address: Paulnank@au1.ibm.com + + ODS2 is distributed freely for all members of the + VMS community to use. However all derived works + must maintain comments in their source to acknowledge + the contibution of the original author. +*/ + + + +struct dir$rec { + u_word dir$size; + u_word dir$verlimit; + u_byte dir$flags; + u_byte dir$namecount; + char dir$name[1]; +}; + +struct dir$ent { + u_word dir$version; + struct fiddef dir$fid; +}; + + +unsigned direct(struct VCB *vcb,struct dsc$descriptor * fibdsc, + struct dsc$descriptor *filedsc,unsigned short *reslen, + struct dsc$descriptor *resdsc,unsigned action); diff --git a/extracters/ods2/fibdef.h b/extracters/ods2/fibdef.h new file mode 100644 index 0000000..40670e4 --- /dev/null +++ b/extracters/ods2/fibdef.h @@ -0,0 +1,37 @@ +/* Fibdef.h v1.2 Definition of 'struct fibdef' */ + +/* + This is part of ODS2 written by Paul Nankervis, + email address: Paulnank@au1.ibm.com + + ODS2 is distributed freely for all members of the + VMS community to use. However all derived works + must maintain comments in their source to acknowledge + the contibution of the original author. +*/ + + +#if defined(VMS) && !defined(__GNUC__) + +#include + +#else + +#define FIB$M_WILD 0x100 + +struct fibdef { + unsigned fib$l_acctl; + unsigned short fib$w_fid_num; + unsigned short fib$w_fid_seq; + unsigned char fib$b_fid_rvn; + unsigned char fib$b_fid_nmx; + unsigned short fib$w_did_num; + unsigned short fib$w_did_seq; + unsigned char fib$b_did_rvn; + unsigned char fib$b_did_nmx; + unsigned fib$l_wcc; + unsigned fib$w_nmctl; + unsigned fib$l_exsz; + unsigned fib$w_exctl; +}; +#endif diff --git a/extracters/ods2/ods2.c b/extracters/ods2/ods2.c new file mode 100644 index 0000000..759fdad --- /dev/null +++ b/extracters/ods2/ods2.c @@ -0,0 +1,896 @@ +/* ODS2.C v1.2 Mainline ODS2 program */ + +/* + This is part of ODS2 written by Paul Nankervis, + email address: Paulnank@au1.ibm.com + + ODS2 is distributed freely for all members of the + VMS community to use. However all derived works + must maintain comments in their source to acknowledge + the contibution of the original author. + + The modules in ODS2 are:- + + ACCESS.C Routines for accessing ODS2 disks + CACHE.C Routines for managing memory cache + DEVICE.C Routines to maintain device information + DIRECT.C Routines for handling directories + ODS2.C The mainline program + PHYVMS.C Routine to perform physical I/O + RMS.C Routines to handle RMS structures + VMSTIME.C Routines to handle VMS times + + On non-VMS platforms PHYVMS.C should be replaced as follows:- + + OS/2 PHYOS2.C + Windows 95/NT PHYNT.C + + For example under OS/2 the program is compiled using the GCC + compiler with the single command:- + + gcc -fdollars-in-identifiers ods2.c,rms.c,direct.c, + access.c,device.c,cache.c,phyos2.c,vmstime.c +*/ + +/* This version will compile and run using normal VMS I/O by + defining VMSIO +*/ + +/* This is the top level set of routines. It is fairly + simple minded asking the user for a command, doing some + primitive command parsing, and then calling a set of routines + to perform whatever function is required (for example COPY). + Some routines are implemented in different ways to test the + underlying routines - for example TYPE is implemented without + a NAM block meaning that it cannot support wildcards... + (sorry! - could be easily fixed though!) +*/ + +#define DEBUGx on +#define VMSIOx on + +#include +#include +#include +#include +#include "descrip.h" +#include "ssdef.h" + +#ifdef VMSIO +#include +#include +unsigned sys$setddir(); +#else +#include "rms.h" +#include "access.h" +#endif + + +#define PRINT_ATTR (FAB$M_CR | FAB$M_PRN | FAB$M_FTN) + + + +/* keycomp: routine to compare parameter to a keyword - case insensitive! */ + +int keycomp(char *param,char *keywrd) +{ + while (*param != '\0') { + if (tolower(*param++) != *keywrd++) return 0; + } + return 1; +} + + +/* checkquals: routine to find a qualifer in a list of possible values */ + +int checkquals(char *qualset[],int qualc,char *qualv[]) +{ + int result = 0; + while (qualc-- > 0) { + int i = 0; + while (qualset[i] != NULL) { + if (keycomp(qualv[qualc],qualset[i])) { + result |= 1 << i; + i = -1; + break; + } + i++; + } + if (i >= 0) printf("%%ODS2-W-ILLQUAL, Unknown qualifer '%s' ignored\n",qualv[qualc]); + } + return result; +} + + +/* dir: a directory routine */ + +char *dirquals[] = {"date","file","size",NULL}; + +unsigned dir(int argc,char *argv[],int qualc,char *qualv[]) +{ + char res[NAM$C_MAXRSS + 1],rsa[NAM$C_MAXRSS + 1]; + int sts,options; + int filecount = 0; + struct NAM nam = cc$rms_nam; + struct FAB fab = cc$rms_fab; + struct XABDAT dat = cc$rms_xabdat; + struct XABFHC fhc = cc$rms_xabfhc; + nam.nam$l_esa = res; + nam.nam$b_ess = NAM$C_MAXRSS; + fab.fab$l_nam = &nam; + fab.fab$l_xab = &dat; + dat.xab$l_nxt = &fhc; + fab.fab$l_fna = argv[1]; + fab.fab$b_fns = strlen(fab.fab$l_fna); + fab.fab$l_dna = "*.*;*"; + fab.fab$b_dns = strlen(fab.fab$l_dna); + options = checkquals(dirquals,qualc,qualv); + sts = sys$parse(&fab); + if (sts & 1) { + char dir[NAM$C_MAXRSS + 1]; + int namelen; + int dirlen = 0; + int dirfiles = 0,dircount = 0; + int dirblocks = 0,totblocks = 0; + int printcol = 0; +#ifdef DEBUG + res[nam.nam$b_esl] = '\0'; + printf("Parse: %s\n",res); +#endif + nam.nam$l_rsa = rsa; + nam.nam$b_rss = NAM$C_MAXRSS; + fab.fab$l_fop = FAB$M_NAM; + while ((sts = sys$search(&fab)) & 1) { + if (dirlen != nam.nam$b_dev + nam.nam$b_dir || + memcmp(rsa,dir,nam.nam$b_dev + nam.nam$b_dir) != 0) { + if (dirfiles > 0) { + if (printcol > 0) printf("\n"); + printf("\nTotal of %d file%s",dirfiles,(dirfiles == 1 ? "" : "s")); + if (options & 4) { + printf(", %d block%s.\n",dirblocks,(dirblocks == 1 ? "" : "s")); + } else { + fputs(".\n",stdout); + } + } + dirlen = nam.nam$b_dev + nam.nam$b_dir; + memcpy(dir,rsa,dirlen); + dir[dirlen] = '\0'; + printf("\nDirectory %s\n\n",dir); + filecount += dirfiles; + totblocks += dirblocks; + dircount++; + dirfiles = 0; + dirblocks = 0; + printcol = 0; + } + rsa[nam.nam$b_rsl] = '\0'; + namelen = nam.nam$b_name + nam.nam$b_type + nam.nam$b_ver; + if (options == 0) { + if (printcol > 0) { + int newcol = (printcol + 20) / 20 * 20; + if (newcol + namelen >= 80) { + fputs("\n",stdout); + printcol = 0; + } else { + printf("%*s",newcol - printcol," "); + printcol = newcol; + } + } + fputs(rsa + dirlen,stdout); + printcol += namelen; + } else { + if (namelen > 18) { + printf("%s\n ",rsa + dirlen); + } else { + printf("%-19s",rsa + dirlen); + } + sts = sys$open(&fab); + if ((sts & 1) == 0) { + printf("Open error: %d\n",sts); + } else { + sts = sys$close(&fab); + if (options & 2) { + char fileid[100]; + sprintf(fileid,"(%d,%d,%d)", + (nam.nam$b_fid_nmx << 16) | nam.nam$w_fid_num, + nam.nam$w_fid_seq,nam.nam$b_fid_rvn); + printf(" %-22s",fileid); + } + if (options & 4) { + unsigned filesize = fhc.xab$l_ebk; + if (fhc.xab$w_ffb == 0) filesize--; + printf("%9d",filesize); + dirblocks += filesize; + } + if (options & 1) { + char tim[24]; + struct dsc$descriptor timdsc; + timdsc.dsc$w_length = 23; + timdsc.dsc$a_pointer = tim; + sts = sys$asctim(0,&timdsc,&dat.xab$q_cdt,0); + if ((sts & 1) == 0) printf("Asctim error: %d\n",sts); + tim[23] = '\0'; + printf(" %s",tim); + } + printf("\n"); + } + } + dirfiles++; + } + if (sts == RMS$_NMF) sts = 1; + if (printcol > 0) printf("\n"); + if (dirfiles > 0) { + printf("\nTotal of %d file%s",dirfiles,(dirfiles == 1 ? "" : "s")); + if (options & 4) { + printf(", %d block%s.\n",dirblocks,(dirblocks == 1 ? "" : "s")); + } else { + fputs(".\n",stdout); + } + filecount += dirfiles; + totblocks += dirblocks; + if (dircount > 1) { + printf("\nGrand total of %d director%s, %d file%s", + dircount,(dircount == 1 ? "y" : "ies"), + filecount,(filecount == 1 ? "" : "s")); + if (options & 4) { + printf(", %d block%s.\n",totblocks,(totblocks == 1 ? "" : "s")); + } else { + fputs(".\n",stdout); + } + } + } + } + if (sts & 1) { + if (filecount < 1) printf("%%DIRECT-W-NOFILES, no files found\n"); + } else { + printf("%%DIR-E-ERROR Status: %d\n",sts); + } + return sts; +} + + +/* copy: a file copy routine */ + +#define MAXREC 32767 + +unsigned copy(int argc,char *argv[],int qualc,char *qualv[]) +{ + int sts; + struct NAM nam = cc$rms_nam; + struct FAB fab = cc$rms_fab; + char res[NAM$C_MAXRSS + 1],rsa[NAM$C_MAXRSS + 1]; + int filecount = 0; + nam.nam$l_esa = res; + nam.nam$b_ess = NAM$C_MAXRSS; + fab.fab$l_nam = &nam; + fab.fab$l_fna = argv[1]; + fab.fab$b_fns = strlen(fab.fab$l_fna); + sts = sys$parse(&fab); + if (sts & 1) { + nam.nam$l_rsa = rsa; + nam.nam$b_rss = NAM$C_MAXRSS; + fab.fab$l_fop = FAB$M_NAM; + while ((sts = sys$search(&fab)) & 1) { + sts = sys$open(&fab); + if ((sts & 1) == 0) { + printf("%%COPY-F-OPENFAIL, Open error: %d\n",sts); + perror("-COPY-F-ERR "); + } else { + struct RAB rab = cc$rms_rab; + rab.rab$l_fab = &fab; + if ((sts = sys$connect(&rab)) & 1) { + FILE *tof; + char name[NAM$C_MAXRSS + 1]; + unsigned records = 0; + { + char *out = name,*inp = argv[2]; + int dot = 0; + while (*inp != '\0') { + if (*inp == '*') { + inp++; + if (dot) { + memcpy(out,nam.nam$l_type + 1,nam.nam$b_type - 1); + out += nam.nam$b_type - 1; + } else { + unsigned length = nam.nam$b_name; + if (*inp == '\0') length += nam.nam$b_type; + memcpy(out,nam.nam$l_name,length); + out += length; + } + } else { + if (*inp == '.') { + dot = 1; + } else { + if (strchr(":]\\/",*inp)) dot = 0; + } + *out++ = *inp++; + } + } + *out++ = '\0'; + } + tof = fopen(name,"w"); + if (tof == NULL) { + printf("%%COPY-F-OPENOUT, Could not open %s\n",name); + perror("-COPY-F-ERR "); + } else { + char rec[MAXREC + 2]; + filecount++; + rab.rab$l_ubf = rec; + rab.rab$w_usz = MAXREC; + while ((sts = sys$get(&rab)) & 1) { + unsigned rsz = rab.rab$w_rsz; + if (fab.fab$b_rat & PRINT_ATTR) rec[rsz++] = '\n'; + if (fwrite(rec,rsz,1,tof) == 1) { + records++; + } else { + printf("%%COPY-F- fwrite error!!\n"); + perror("-COPY-F-ERR "); + break; + } + } + if (fclose(tof)) { + printf("%%COPY-F- fclose error!!\n"); + perror("-COPY-F-ERR "); + } + } + sys$disconnect(&rab); + if (sts == RMS$_EOF) { + rsa[nam.nam$b_rsl] = '\0'; + printf("%%COPY-S-COPIED, %s copied to %s (%d record%s)\n", + rsa,name,records,(records == 1 ? "" : "s")); + sts = 1; + } + } + sys$close(&fab); + } + } + if (sts == RMS$_NMF) sts = 1; + } + if (sts & 1) { + if (filecount > 0) printf("%%COPY-S-NEWFILES, %d file%s created\n", + filecount,(filecount == 1 ? "" : "s")); + } else { + printf("%%COPY-F-ERROR Status: %d\n",sts); + } + return sts; +} + + +/* diff: a simple file difference routine */ + +unsigned diff(int argc,char *argv[],int qualc,char *qualv[]) +{ + int sts; + struct FAB fab = cc$rms_fab; + FILE *tof; + int records = 0; + fab.fab$l_fna = argv[1]; + fab.fab$b_fns = strlen(fab.fab$l_fna); + tof = fopen(argv[2],"r"); + if (tof == NULL) { + printf("Could not open file %s\n",argv[1]); + sts = 0; + } else { + if ((sts = sys$open(&fab)) & 1) { + struct RAB rab = cc$rms_rab; + rab.rab$l_fab = &fab; + if ((sts = sys$connect(&rab)) & 1) { + char rec[MAXREC + 2],cpy[MAXREC + 1]; + rab.rab$l_ubf = rec; + rab.rab$w_usz = MAXREC; + while ((sts = sys$get(&rab)) & 1) { + strcpy(rec + rab.rab$w_rsz,"\n"); + fgets(cpy,MAXREC,tof); + if (strcmp(rec,cpy) != 0) { + printf("%%DIFF-F-DIFFERENT Files are different!\n"); + sts = 4; + break; + } else { + records++; + } + } + sys$disconnect(&rab); + } + sys$close(&fab); + } + fclose(tof); + if (sts == RMS$_EOF) sts = 1; + } + if (sts & 1) { + printf("%%DIFF-I-Compared %d records\n",records); + } else { + printf("%%DIFF-F-Error %d in difference\n",sts); + } + return sts; +} + + +/* typ: a file TYPE routine */ + +unsigned typ(int argc,char *argv[],int qualc,char *qualv[]) +{ + int sts; + int records = 0; + struct FAB fab = cc$rms_fab; + fab.fab$l_fna = argv[1]; + fab.fab$b_fns = strlen(fab.fab$l_fna); + if ((sts = sys$open(&fab)) & 1) { + struct RAB rab = cc$rms_rab; + rab.rab$l_fab = &fab; + if ((sts = sys$connect(&rab)) & 1) { + char rec[MAXREC + 2]; + rab.rab$l_ubf = rec; + rab.rab$w_usz = MAXREC; + while ((sts = sys$get(&rab)) & 1) { + unsigned rsz = rab.rab$w_rsz; + if (fab.fab$b_rat & PRINT_ATTR) rec[rsz++] = '\n'; + rec[rsz++] = '\0'; + fputs(rec,stdout); + records++; + } + sys$disconnect(&rab); + } + sys$close(&fab); + if (sts == RMS$_EOF) sts = 1; + } + if ((sts & 1) == 0) { + printf("%%TYPE-F-ERROR Status: %d\n",sts); + } + return sts; +} + + + +/* search: a simple file search routine */ + +unsigned search(int argc,char *argv[],int qualc,char *qualv[]) +{ + int sts = 0; + int filecount = 0; + int findcount = 0; + char res[NAM$C_MAXRSS + 1],rsa[NAM$C_MAXRSS + 1]; + struct NAM nam = cc$rms_nam; + struct FAB fab = cc$rms_fab; + register char *searstr = argv[2]; + register char firstch = tolower(*searstr++); + register char *searend = searstr + strlen(searstr); + { + char *str = searstr; + while (str < searend) { + *str = tolower(*str); + str++; + } + } + nam = cc$rms_nam; + fab = cc$rms_fab; + nam.nam$l_esa = res; + nam.nam$b_ess = NAM$C_MAXRSS; + fab.fab$l_nam = &nam; + fab.fab$l_fna = argv[1]; + fab.fab$b_fns = strlen(fab.fab$l_fna); + fab.fab$l_dna = ""; + fab.fab$b_dns = strlen(fab.fab$l_dna); + sts = sys$parse(&fab); + if (sts & 1) { + nam.nam$l_rsa = rsa; + nam.nam$b_rss = NAM$C_MAXRSS; + fab.fab$l_fop = FAB$M_NAM; + while ((sts = sys$search(&fab)) & 1) { + sts = sys$open(&fab); + if ((sts & 1) == 0) { + printf("%%SEARCH-F-OPENFAIL, Open error: %d\n",sts); + } else { + struct RAB rab = cc$rms_rab; + rab.rab$l_fab = &fab; + if ((sts = sys$connect(&rab)) & 1) { + int printname = 1; + char rec[MAXREC + 2]; + filecount++; + rab.rab$l_ubf = rec; + rab.rab$w_usz = MAXREC; + while ((sts = sys$get(&rab)) & 1) { + register char *strng = rec; + register char *strngend = strng + (rab.rab$w_rsz - (searend - searstr)); + while (strng < strngend) { + register char ch = *strng++; + if (ch == firstch || (ch >= 'A' && ch <= 'Z' && ch + 32 == firstch)) { + register char *str = strng; + register char *cmp = searstr; + while (cmp < searend) { + register char ch2 = *str++; + ch = *cmp; + if (ch2 != ch && (ch2 < 'A' || ch2 > 'Z' || ch2 + 32 != ch)) break; + cmp++; + } + if (cmp >= searend) { + findcount++; + rec[rab.rab$w_rsz] = '\0'; + if (printname) { + rsa[nam.nam$b_rsl] = '\0'; + printf("\n******************************\n%s\n\n",rsa); + printname = 0; + } + fputs(rec,stdout); + if (fab.fab$b_rat & PRINT_ATTR) fputc('\n',stdout); + break; + } + } + } + } + sys$disconnect(&rab); + } + if (sts == SS$_NOTINSTALL) { + printf("%%SEARCH-W-NOIMPLEM, file operation not implemented\n"); + sts = 1; + } + sys$close(&fab); + } + } + if (sts == RMS$_NMF || sts == RMS$_FNF) sts = 1; + } + if (sts & 1) { + if (filecount < 1) { + printf("%%SEARCH-W-NOFILES, no files found\n"); + } else { + if (findcount < 1) printf("%%SEARCH-I-NOMATCHES, no strings matched\n"); + } + } else { + printf("%%SEARCH-F-ERROR Status: %d\n",sts); + } + return sts; +} + + +/* del: you don't want to know! */ + +unsigned del(int argc,char *argv[],int qualc,char *qualv[]) +{ + int sts = 0; + struct NAM nam = cc$rms_nam; + struct FAB fab = cc$rms_fab; + char res[NAM$C_MAXRSS + 1],rsa[NAM$C_MAXRSS + 1]; + int filecount = 0; + nam.nam$l_esa = res; + nam.nam$b_ess = NAM$C_MAXRSS; + fab.fab$l_nam = &nam; + fab.fab$l_fna = argv[1]; + fab.fab$b_fns = strlen(fab.fab$l_fna); + printf("WARNING! This bit is broken - volume corruption VERY likely!\n"); + sts = sys$parse(&fab); + if (sts & 1) { + if (nam.nam$b_ver < 2) { + printf("%%DELETE-F-NOVER, you must specify a version!!\n"); + } else { + nam.nam$l_rsa = rsa; + nam.nam$b_rss = NAM$C_MAXRSS; + fab.fab$l_fop = FAB$M_NAM; + while ((sts = sys$search(&fab)) & 1) { + sts = sys$erase(&fab); + if ((sts & 1) == 0) { + printf("%%DELETE-F-DELERR, Delete error: %d\n",sts); + } else { + filecount++; + rsa[nam.nam$b_rsl] = '\0'; + printf("%%DELETE-I-DELETED, Deleted %s\n",rsa); + } + } + if (sts == RMS$_NMF) sts = 1; + } + if (sts & 1) { + if (filecount < 1) { + printf("%%DELETE-W-NOFILES, no files deleted\n"); + } + } else { + printf("%%DELETE-F-ERROR Status: %d\n",sts); + } + } + return sts; +} + + +/* show: the show command */ + +unsigned show(int argc,char *argv[],int qualc,char *qualv[]) +{ + unsigned sts = 1; + if (keycomp(argv[1],"default")) { + unsigned short curlen; + char curdir[NAM$C_MAXRSS + 1]; + struct dsc$descriptor curdsc; + curdsc.dsc$w_length = NAM$C_MAXRSS; + curdsc.dsc$a_pointer = curdir; + if ((sts = sys$setddir(NULL,&curlen,&curdsc)) & 1) { + curdir[curlen] = '\0'; + printf(" %s\n",curdir); + } else { + printf("Error %d getting default\n",sts); + } + } else { + if (keycomp(argv[1],"time")) { + char timstr[24]; + unsigned short timlen; + struct dsc$descriptor timdsc; + timdsc.dsc$w_length = 23; + timdsc.dsc$a_pointer = timstr; + sys$asctim(&timlen,&timdsc,NULL,0); + timstr[timlen] = '\0'; + printf(" %s\n",timstr); + } else { + printf("%%SHOW-W-WHAT '%s'?\n",argv[1]); + } + } + return sts; +} + +/* set: the set command */ + +unsigned set(int argc,char *argv[],int qualc,char *qualv[]) +{ + unsigned sts = 1; + if (keycomp(argv[1],"default")) { + struct dsc$descriptor defdsc; + defdsc.dsc$a_pointer = argv[2]; + defdsc.dsc$w_length = strlen(defdsc.dsc$a_pointer); + if (((sts = sys$setddir(&defdsc,NULL,NULL)) & 1) == 0) { + printf("Error %d setting default to %s\n",sts,argv[2]); + } + } else { + printf("%%SET-W-WHAT '%s'?\n",argv[1]); + } + return sts; +} + + +#ifndef VMSIO + +/* The bits we need when we don't have real VMS routines underneath... */ + +unsigned dodismount(int argc,char *argv[],int qualc,char *qualv[]) +{ + struct DEV *dev; + register int sts = device_lookup(strlen(argv[1]),argv[1],0,&dev); + if (sts & 1) { + if (dev->vcb != NULL) { + sts = dismount(dev->vcb); + } else { + sts = SS$_DEVNOTMOUNT; + } + } + if ((sts & 1) == 0) printf("%%DISMOUNT-E-STATUS Error: %d\n",sts); + return sts; +} + +char *mouquals[] = {"write",NULL}; + +unsigned domount(int argc,char *argv[],int qualc,char *qualv[]) +{ + char *dev = argv[1]; + char *lab = argv[2]; + int sts = 1,devices = 0; + char *devs[100],*labs[100]; + int options = checkquals(mouquals,qualc,qualv); + while (*lab != '\0') { + labs[devices++] = lab; + while (*lab != ',' && *lab != '\0') lab++; + if (*lab != '\0') { + *lab++ = '\0'; + } else { + break; + } + } + devices = 0; + while (*dev != '\0') { + devs[devices++] = dev; + while (*dev != ',' && *dev != '\0') dev++; + if (*dev != '\0') { + *dev++ = '\0'; + } else { + break; + } + } + if (devices > 0) { + unsigned i; + struct VCB *vcb; + sts = mount(options,devices,devs,labs,&vcb); + if (sts & 1) { + for (i = 0; i < vcb->devices; i++) + if (vcb->vcbdev[i].dev != NULL) + printf("%%MOUNT-I-MOUNTED, Volume %12.12s mounted on %s\n", + vcb->vcbdev[i].home.hm2$t_volname,vcb->vcbdev[i].dev->devnam); + } else { + printf("Mount failed with %d\n",sts); + } + } + return sts; +} + + +void directshow(void); +void phyio_show(void); + +/* statis: print some simple statistics */ + +unsigned statis(int argc,char *argv[],int qualc,char *qualv[]) +{ + printf("Statistics:-\n"); + directshow(); + cacheshow(); + phyio_show(); + return 1; +} + +/* dump: a simple debugging aid */ + +unsigned dump(int argc,char *argv[],int qualc,char *qualv[]) +{ + printf("Cache Dump:-\n"); + cachedump(); + return 1; +} +#endif + + +/* help: a routine to print a pre-prepared help text... */ + +unsigned help(int argc,char *argv[],int qualc,char *qualv[]) +{ + printf("\nODS2 v1.2\n"); + printf(" Please send problems/comments to Paulnank@au1.ibm.com\n"); + printf(" Commands are:\n"); + printf(" copy difference directory exit\n"); + printf(" mount show_default show_time search\n"); + printf(" set_default type\n"); + printf(" Example:-\n $ mount e:\n"); + printf(" $ search e:[vms$common.decc*...]*.h rms$_wld\n"); + printf(" $ set default e:[sys0.sysmgr]\n"); + printf(" $ copy *.com;-1 c:\\*.*\n"); + printf(" $ directory/file/size/date [-.sys*...].%%\n"); + printf(" $ exit\n"); + return 1; +} + + +/* informaion about the commands we know... */ + +struct CMDSET { + char *name; + unsigned (*proc) (int argc,char *argv[],int qualc,char *qualv[]); + unsigned int minlen; + unsigned int minargs; + unsigned int maxargs; + unsigned int maxquals; +} cmdset[] = { + { + "copy",copy,3,3,3,0 +}, + { + "delete",del,3,2,2,0 +}, + { + "difference",diff,3,3,3,0 +}, + { + "directory",dir,3,1,2,6 +}, + { + "exit",NULL,2,0,0,0 +}, + { + "help",help,2,1,1,0 +}, + { + "show",show,2,2,2,0 +}, + { + "search",search,3,3,3,0 +}, + { + "set",set,3,2,3,0 +}, +#ifndef VMSIO + { + "dismount",dodismount,3,2,2,0 +}, + { + "mount",domount,3,2,3,2 +}, + { + "statistics",statis,3,1,1,0 +}, + { + "dump",dump,3,1,1,0 +}, +#endif + { + "type",typ,3,2,2,0 +}, + { + NULL,NULL,0,0,0,0 +} +}; + + +/* cmdexecute: identify and execute a command */ + +int cmdexecute(unsigned int argc,char *argv[],unsigned int qualc,char *qualv[]) +{ + char *ptr = argv[0]; + struct CMDSET *cmd = cmdset; + unsigned cmdsiz = strlen(ptr); + while (*ptr != '\0') { + *ptr = tolower(*ptr); + ptr++; + } + while (cmd->name != NULL) { + if (cmdsiz >= cmd->minlen && cmdsiz <= strlen(cmd->name)) { + if (keycomp(argv[0],cmd->name)) { + if (cmd->proc == NULL) { + return 0; + } else { + if (argc < cmd->minargs || argc > cmd->maxargs) { + printf("%%ODS2-E-PARAMS, Incorrect number of command parameters\n"); + } else { + if (qualc > cmd->maxquals) { + printf("%%ODS2-E-QUALS, Too many command qualifiers\n"); + } else { + (*cmd->proc) (argc,argv,qualc,qualv); +#ifndef VMSIO + cacheflush(); +#endif + } + } + return 1; + } + } + } + cmd++; + } + printf("%%ODS2-E-ILLCMD, Illegal or ambiguous command '%s'\n",argv[0]); + return 1; +} + +/* cmdsplit: break a command line into its components */ + +int cmdsplit(char *str) +{ + int argc = 0,qualc = 0; + char *argv[32],*qualv[32]; + char *sp = str; + int i; + for (i = 0; i < 32; i++) argv[i] = qualv[i] = ""; + while (*sp != '\0') { + while (*sp == ' ') sp++; + if (*sp != '\0') { + if (*sp == '/') { + *sp++ = '\0'; + qualv[qualc++] = sp; + } else { + argv[argc++] = sp; + } + while (*sp != ' ' && *sp != '/' && *sp != '\0') sp++; + if (*sp == '\0') { + break; + } else { + if (*sp != '/') *sp++ = '\0'; + } + } + } + if (argc > 0) return cmdexecute(argc,argv,qualc,qualv); + return 1; +} + + +/* main: the simple mainline of this puppy... */ + +int main(int argc,char *argv[]) +{ + char str[2048]; + str[sizeof(str)-1] = 0; + printf(" ODS2 v1.2\n"); + while (1) { + printf("$> "); + if (fgets(str, sizeof(str)-1, stdin) == NULL) break; + if (strlen(str)) if ((cmdsplit(str) & 1) == 0) break; + } + return 1; +} diff --git a/extracters/ods2/ods2.c.bak b/extracters/ods2/ods2.c.bak new file mode 100644 index 0000000..49825b2 --- /dev/null +++ b/extracters/ods2/ods2.c.bak @@ -0,0 +1,895 @@ +/* ODS2.C v1.2 Mainline ODS2 program */ + +/* + This is part of ODS2 written by Paul Nankervis, + email address: Paulnank@au1.ibm.com + + ODS2 is distributed freely for all members of the + VMS community to use. However all derived works + must maintain comments in their source to acknowledge + the contibution of the original author. + + The modules in ODS2 are:- + + ACCESS.C Routines for accessing ODS2 disks + CACHE.C Routines for managing memory cache + DEVICE.C Routines to maintain device information + DIRECT.C Routines for handling directories + ODS2.C The mainline program + PHYVMS.C Routine to perform physical I/O + RMS.C Routines to handle RMS structures + VMSTIME.C Routines to handle VMS times + + On non-VMS platforms PHYVMS.C should be replaced as follows:- + + OS/2 PHYOS2.C + Windows 95/NT PHYNT.C + + For example under OS/2 the program is compiled using the GCC + compiler with the single command:- + + gcc -fdollars-in-identifiers ods2.c,rms.c,direct.c, + access.c,device.c,cache.c,phyos2.c,vmstime.c +*/ + +/* This version will compile and run using normal VMS I/O by + defining VMSIO +*/ + +/* This is the top level set of routines. It is fairly + simple minded asking the user for a command, doing some + primitive command parsing, and then calling a set of routines + to perform whatever function is required (for example COPY). + Some routines are implemented in different ways to test the + underlying routines - for example TYPE is implemented without + a NAM block meaning that it cannot support wildcards... + (sorry! - could be easily fixed though!) +*/ + +#define DEBUGx on +#define VMSIOx on + +#include +#include +#include +#include +#include "descrip.h" +#include "ssdef.h" + +#ifdef VMSIO +#include +#include +unsigned sys$setddir(); +#else +#include "rms.h" +#include "access.h" +#endif + + +#define PRINT_ATTR (FAB$M_CR | FAB$M_PRN | FAB$M_FTN) + + + +/* keycomp: routine to compare parameter to a keyword - case insensitive! */ + +int keycomp(char *param,char *keywrd) +{ + while (*param != '\0') { + if (tolower(*param++) != *keywrd++) return 0; + } + return 1; +} + + +/* checkquals: routine to find a qualifer in a list of possible values */ + +int checkquals(char *qualset[],int qualc,char *qualv[]) +{ + int result = 0; + while (qualc-- > 0) { + int i = 0; + while (qualset[i] != NULL) { + if (keycomp(qualv[qualc],qualset[i])) { + result |= 1 << i; + i = -1; + break; + } + i++; + } + if (i >= 0) printf("%%ODS2-W-ILLQUAL, Unknown qualifer '%s' ignored\n",qualv[qualc]); + } + return result; +} + + +/* dir: a directory routine */ + +char *dirquals[] = {"date","file","size",NULL}; + +unsigned dir(int argc,char *argv[],int qualc,char *qualv[]) +{ + char res[NAM$C_MAXRSS + 1],rsa[NAM$C_MAXRSS + 1]; + int sts,options; + int filecount = 0; + struct NAM nam = cc$rms_nam; + struct FAB fab = cc$rms_fab; + struct XABDAT dat = cc$rms_xabdat; + struct XABFHC fhc = cc$rms_xabfhc; + nam.nam$l_esa = res; + nam.nam$b_ess = NAM$C_MAXRSS; + fab.fab$l_nam = &nam; + fab.fab$l_xab = &dat; + dat.xab$l_nxt = &fhc; + fab.fab$l_fna = argv[1]; + fab.fab$b_fns = strlen(fab.fab$l_fna); + fab.fab$l_dna = "*.*;*"; + fab.fab$b_dns = strlen(fab.fab$l_dna); + options = checkquals(dirquals,qualc,qualv); + sts = sys$parse(&fab); + if (sts & 1) { + char dir[NAM$C_MAXRSS + 1]; + int namelen; + int dirlen = 0; + int dirfiles = 0,dircount = 0; + int dirblocks = 0,totblocks = 0; + int printcol = 0; +#ifdef DEBUG + res[nam.nam$b_esl] = '\0'; + printf("Parse: %s\n",res); +#endif + nam.nam$l_rsa = rsa; + nam.nam$b_rss = NAM$C_MAXRSS; + fab.fab$l_fop = FAB$M_NAM; + while ((sts = sys$search(&fab)) & 1) { + if (dirlen != nam.nam$b_dev + nam.nam$b_dir || + memcmp(rsa,dir,nam.nam$b_dev + nam.nam$b_dir) != 0) { + if (dirfiles > 0) { + if (printcol > 0) printf("\n"); + printf("\nTotal of %d file%s",dirfiles,(dirfiles == 1 ? "" : "s")); + if (options & 4) { + printf(", %d block%s.\n",dirblocks,(dirblocks == 1 ? "" : "s")); + } else { + fputs(".\n",stdout); + } + } + dirlen = nam.nam$b_dev + nam.nam$b_dir; + memcpy(dir,rsa,dirlen); + dir[dirlen] = '\0'; + printf("\nDirectory %s\n\n",dir); + filecount += dirfiles; + totblocks += dirblocks; + dircount++; + dirfiles = 0; + dirblocks = 0; + printcol = 0; + } + rsa[nam.nam$b_rsl] = '\0'; + namelen = nam.nam$b_name + nam.nam$b_type + nam.nam$b_ver; + if (options == 0) { + if (printcol > 0) { + int newcol = (printcol + 20) / 20 * 20; + if (newcol + namelen >= 80) { + fputs("\n",stdout); + printcol = 0; + } else { + printf("%*s",newcol - printcol," "); + printcol = newcol; + } + } + fputs(rsa + dirlen,stdout); + printcol += namelen; + } else { + if (namelen > 18) { + printf("%s\n ",rsa + dirlen); + } else { + printf("%-19s",rsa + dirlen); + } + sts = sys$open(&fab); + if ((sts & 1) == 0) { + printf("Open error: %d\n",sts); + } else { + sts = sys$close(&fab); + if (options & 2) { + char fileid[100]; + sprintf(fileid,"(%d,%d,%d)", + (nam.nam$b_fid_nmx << 16) | nam.nam$w_fid_num, + nam.nam$w_fid_seq,nam.nam$b_fid_rvn); + printf(" %-22s",fileid); + } + if (options & 4) { + unsigned filesize = fhc.xab$l_ebk; + if (fhc.xab$w_ffb == 0) filesize--; + printf("%9d",filesize); + dirblocks += filesize; + } + if (options & 1) { + char tim[24]; + struct dsc$descriptor timdsc; + timdsc.dsc$w_length = 23; + timdsc.dsc$a_pointer = tim; + sts = sys$asctim(0,&timdsc,&dat.xab$q_cdt,0); + if ((sts & 1) == 0) printf("Asctim error: %d\n",sts); + tim[23] = '\0'; + printf(" %s",tim); + } + printf("\n"); + } + } + dirfiles++; + } + if (sts == RMS$_NMF) sts = 1; + if (printcol > 0) printf("\n"); + if (dirfiles > 0) { + printf("\nTotal of %d file%s",dirfiles,(dirfiles == 1 ? "" : "s")); + if (options & 4) { + printf(", %d block%s.\n",dirblocks,(dirblocks == 1 ? "" : "s")); + } else { + fputs(".\n",stdout); + } + filecount += dirfiles; + totblocks += dirblocks; + if (dircount > 1) { + printf("\nGrand total of %d director%s, %d file%s", + dircount,(dircount == 1 ? "y" : "ies"), + filecount,(filecount == 1 ? "" : "s")); + if (options & 4) { + printf(", %d block%s.\n",totblocks,(totblocks == 1 ? "" : "s")); + } else { + fputs(".\n",stdout); + } + } + } + } + if (sts & 1) { + if (filecount < 1) printf("%%DIRECT-W-NOFILES, no files found\n"); + } else { + printf("%%DIR-E-ERROR Status: %d\n",sts); + } + return sts; +} + + +/* copy: a file copy routine */ + +#define MAXREC 32767 + +unsigned copy(int argc,char *argv[],int qualc,char *qualv[]) +{ + int sts; + struct NAM nam = cc$rms_nam; + struct FAB fab = cc$rms_fab; + char res[NAM$C_MAXRSS + 1],rsa[NAM$C_MAXRSS + 1]; + int filecount = 0; + nam.nam$l_esa = res; + nam.nam$b_ess = NAM$C_MAXRSS; + fab.fab$l_nam = &nam; + fab.fab$l_fna = argv[1]; + fab.fab$b_fns = strlen(fab.fab$l_fna); + sts = sys$parse(&fab); + if (sts & 1) { + nam.nam$l_rsa = rsa; + nam.nam$b_rss = NAM$C_MAXRSS; + fab.fab$l_fop = FAB$M_NAM; + while ((sts = sys$search(&fab)) & 1) { + sts = sys$open(&fab); + if ((sts & 1) == 0) { + printf("%%COPY-F-OPENFAIL, Open error: %d\n",sts); + perror("-COPY-F-ERR "); + } else { + struct RAB rab = cc$rms_rab; + rab.rab$l_fab = &fab; + if ((sts = sys$connect(&rab)) & 1) { + FILE *tof; + char name[NAM$C_MAXRSS + 1]; + unsigned records = 0; + { + char *out = name,*inp = argv[2]; + int dot = 0; + while (*inp != '\0') { + if (*inp == '*') { + inp++; + if (dot) { + memcpy(out,nam.nam$l_type + 1,nam.nam$b_type - 1); + out += nam.nam$b_type - 1; + } else { + unsigned length = nam.nam$b_name; + if (*inp == '\0') length += nam.nam$b_type; + memcpy(out,nam.nam$l_name,length); + out += length; + } + } else { + if (*inp == '.') { + dot = 1; + } else { + if (strchr(":]\\/",*inp)) dot = 0; + } + *out++ = *inp++; + } + } + *out++ = '\0'; + } + tof = fopen(name,"w"); + if (tof == NULL) { + printf("%%COPY-F-OPENOUT, Could not open %s\n",name); + perror("-COPY-F-ERR "); + } else { + char rec[MAXREC + 2]; + filecount++; + rab.rab$l_ubf = rec; + rab.rab$w_usz = MAXREC; + while ((sts = sys$get(&rab)) & 1) { + unsigned rsz = rab.rab$w_rsz; + if (fab.fab$b_rat & PRINT_ATTR) rec[rsz++] = '\n'; + if (fwrite(rec,rsz,1,tof) == 1) { + records++; + } else { + printf("%%COPY-F- fwrite error!!\n"); + perror("-COPY-F-ERR "); + break; + } + } + if (fclose(tof)) { + printf("%%COPY-F- fclose error!!\n"); + perror("-COPY-F-ERR "); + } + } + sys$disconnect(&rab); + if (sts == RMS$_EOF) { + rsa[nam.nam$b_rsl] = '\0'; + printf("%%COPY-S-COPIED, %s copied to %s (%d record%s)\n", + rsa,name,records,(records == 1 ? "" : "s")); + sts = 1; + } + } + sys$close(&fab); + } + } + if (sts == RMS$_NMF) sts = 1; + } + if (sts & 1) { + if (filecount > 0) printf("%%COPY-S-NEWFILES, %d file%s created\n", + filecount,(filecount == 1 ? "" : "s")); + } else { + printf("%%COPY-F-ERROR Status: %d\n",sts); + } + return sts; +} + + +/* diff: a simple file difference routine */ + +unsigned diff(int argc,char *argv[],int qualc,char *qualv[]) +{ + int sts; + struct FAB fab = cc$rms_fab; + FILE *tof; + int records = 0; + fab.fab$l_fna = argv[1]; + fab.fab$b_fns = strlen(fab.fab$l_fna); + tof = fopen(argv[2],"r"); + if (tof == NULL) { + printf("Could not open file %s\n",argv[1]); + sts = 0; + } else { + if ((sts = sys$open(&fab)) & 1) { + struct RAB rab = cc$rms_rab; + rab.rab$l_fab = &fab; + if ((sts = sys$connect(&rab)) & 1) { + char rec[MAXREC + 2],cpy[MAXREC + 1]; + rab.rab$l_ubf = rec; + rab.rab$w_usz = MAXREC; + while ((sts = sys$get(&rab)) & 1) { + strcpy(rec + rab.rab$w_rsz,"\n"); + fgets(cpy,MAXREC,tof); + if (strcmp(rec,cpy) != 0) { + printf("%%DIFF-F-DIFFERENT Files are different!\n"); + sts = 4; + break; + } else { + records++; + } + } + sys$disconnect(&rab); + } + sys$close(&fab); + } + fclose(tof); + if (sts == RMS$_EOF) sts = 1; + } + if (sts & 1) { + printf("%%DIFF-I-Compared %d records\n",records); + } else { + printf("%%DIFF-F-Error %d in difference\n",sts); + } + return sts; +} + + +/* typ: a file TYPE routine */ + +unsigned typ(int argc,char *argv[],int qualc,char *qualv[]) +{ + int sts; + int records = 0; + struct FAB fab = cc$rms_fab; + fab.fab$l_fna = argv[1]; + fab.fab$b_fns = strlen(fab.fab$l_fna); + if ((sts = sys$open(&fab)) & 1) { + struct RAB rab = cc$rms_rab; + rab.rab$l_fab = &fab; + if ((sts = sys$connect(&rab)) & 1) { + char rec[MAXREC + 2]; + rab.rab$l_ubf = rec; + rab.rab$w_usz = MAXREC; + while ((sts = sys$get(&rab)) & 1) { + unsigned rsz = rab.rab$w_rsz; + if (fab.fab$b_rat & PRINT_ATTR) rec[rsz++] = '\n'; + rec[rsz++] = '\0'; + fputs(rec,stdout); + records++; + } + sys$disconnect(&rab); + } + sys$close(&fab); + if (sts == RMS$_EOF) sts = 1; + } + if ((sts & 1) == 0) { + printf("%%TYPE-F-ERROR Status: %d\n",sts); + } + return sts; +} + + + +/* search: a simple file search routine */ + +unsigned search(int argc,char *argv[],int qualc,char *qualv[]) +{ + int sts = 0; + int filecount = 0; + int findcount = 0; + char res[NAM$C_MAXRSS + 1],rsa[NAM$C_MAXRSS + 1]; + struct NAM nam = cc$rms_nam; + struct FAB fab = cc$rms_fab; + register char *searstr = argv[2]; + register char firstch = tolower(*searstr++); + register char *searend = searstr + strlen(searstr); + { + char *str = searstr; + while (str < searend) { + *str = tolower(*str); + str++; + } + } + nam = cc$rms_nam; + fab = cc$rms_fab; + nam.nam$l_esa = res; + nam.nam$b_ess = NAM$C_MAXRSS; + fab.fab$l_nam = &nam; + fab.fab$l_fna = argv[1]; + fab.fab$b_fns = strlen(fab.fab$l_fna); + fab.fab$l_dna = ""; + fab.fab$b_dns = strlen(fab.fab$l_dna); + sts = sys$parse(&fab); + if (sts & 1) { + nam.nam$l_rsa = rsa; + nam.nam$b_rss = NAM$C_MAXRSS; + fab.fab$l_fop = FAB$M_NAM; + while ((sts = sys$search(&fab)) & 1) { + sts = sys$open(&fab); + if ((sts & 1) == 0) { + printf("%%SEARCH-F-OPENFAIL, Open error: %d\n",sts); + } else { + struct RAB rab = cc$rms_rab; + rab.rab$l_fab = &fab; + if ((sts = sys$connect(&rab)) & 1) { + int printname = 1; + char rec[MAXREC + 2]; + filecount++; + rab.rab$l_ubf = rec; + rab.rab$w_usz = MAXREC; + while ((sts = sys$get(&rab)) & 1) { + register char *strng = rec; + register char *strngend = strng + (rab.rab$w_rsz - (searend - searstr)); + while (strng < strngend) { + register char ch = *strng++; + if (ch == firstch || (ch >= 'A' && ch <= 'Z' && ch + 32 == firstch)) { + register char *str = strng; + register char *cmp = searstr; + while (cmp < searend) { + register char ch2 = *str++; + ch = *cmp; + if (ch2 != ch && (ch2 < 'A' || ch2 > 'Z' || ch2 + 32 != ch)) break; + cmp++; + } + if (cmp >= searend) { + findcount++; + rec[rab.rab$w_rsz] = '\0'; + if (printname) { + rsa[nam.nam$b_rsl] = '\0'; + printf("\n******************************\n%s\n\n",rsa); + printname = 0; + } + fputs(rec,stdout); + if (fab.fab$b_rat & PRINT_ATTR) fputc('\n',stdout); + break; + } + } + } + } + sys$disconnect(&rab); + } + if (sts == SS$_NOTINSTALL) { + printf("%%SEARCH-W-NOIMPLEM, file operation not implemented\n"); + sts = 1; + } + sys$close(&fab); + } + } + if (sts == RMS$_NMF || sts == RMS$_FNF) sts = 1; + } + if (sts & 1) { + if (filecount < 1) { + printf("%%SEARCH-W-NOFILES, no files found\n"); + } else { + if (findcount < 1) printf("%%SEARCH-I-NOMATCHES, no strings matched\n"); + } + } else { + printf("%%SEARCH-F-ERROR Status: %d\n",sts); + } + return sts; +} + + +/* del: you don't want to know! */ + +unsigned del(int argc,char *argv[],int qualc,char *qualv[]) +{ + int sts = 0; + struct NAM nam = cc$rms_nam; + struct FAB fab = cc$rms_fab; + char res[NAM$C_MAXRSS + 1],rsa[NAM$C_MAXRSS + 1]; + int filecount = 0; + nam.nam$l_esa = res; + nam.nam$b_ess = NAM$C_MAXRSS; + fab.fab$l_nam = &nam; + fab.fab$l_fna = argv[1]; + fab.fab$b_fns = strlen(fab.fab$l_fna); + printf("WARNING! This bit is broken - volume corruption VERY likely!\n"); + sts = sys$parse(&fab); + if (sts & 1) { + if (nam.nam$b_ver < 2) { + printf("%%DELETE-F-NOVER, you must specify a version!!\n"); + } else { + nam.nam$l_rsa = rsa; + nam.nam$b_rss = NAM$C_MAXRSS; + fab.fab$l_fop = FAB$M_NAM; + while ((sts = sys$search(&fab)) & 1) { + sts = sys$erase(&fab); + if ((sts & 1) == 0) { + printf("%%DELETE-F-DELERR, Delete error: %d\n",sts); + } else { + filecount++; + rsa[nam.nam$b_rsl] = '\0'; + printf("%%DELETE-I-DELETED, Deleted %s\n",rsa); + } + } + if (sts == RMS$_NMF) sts = 1; + } + if (sts & 1) { + if (filecount < 1) { + printf("%%DELETE-W-NOFILES, no files deleted\n"); + } + } else { + printf("%%DELETE-F-ERROR Status: %d\n",sts); + } + } + return sts; +} + + +/* show: the show command */ + +unsigned show(int argc,char *argv[],int qualc,char *qualv[]) +{ + unsigned sts = 1; + if (keycomp(argv[1],"default")) { + unsigned short curlen; + char curdir[NAM$C_MAXRSS + 1]; + struct dsc$descriptor curdsc; + curdsc.dsc$w_length = NAM$C_MAXRSS; + curdsc.dsc$a_pointer = curdir; + if ((sts = sys$setddir(NULL,&curlen,&curdsc)) & 1) { + curdir[curlen] = '\0'; + printf(" %s\n",curdir); + } else { + printf("Error %d getting default\n",sts); + } + } else { + if (keycomp(argv[1],"time")) { + char timstr[24]; + unsigned short timlen; + struct dsc$descriptor timdsc; + timdsc.dsc$w_length = 23; + timdsc.dsc$a_pointer = timstr; + sys$asctim(&timlen,&timdsc,NULL,0); + timstr[timlen] = '\0'; + printf(" %s\n",timstr); + } else { + printf("%%SHOW-W-WHAT '%s'?\n",argv[1]); + } + } + return sts; +} + +/* set: the set command */ + +unsigned set(int argc,char *argv[],int qualc,char *qualv[]) +{ + unsigned sts = 1; + if (keycomp(argv[1],"default")) { + struct dsc$descriptor defdsc; + defdsc.dsc$a_pointer = argv[2]; + defdsc.dsc$w_length = strlen(defdsc.dsc$a_pointer); + if (((sts = sys$setddir(&defdsc,NULL,NULL)) & 1) == 0) { + printf("Error %d setting default to %s\n",sts,argv[2]); + } + } else { + printf("%%SET-W-WHAT '%s'?\n",argv[1]); + } + return sts; +} + + +#ifndef VMSIO + +/* The bits we need when we don't have real VMS routines underneath... */ + +unsigned dodismount(int argc,char *argv[],int qualc,char *qualv[]) +{ + struct DEV *dev; + register int sts = device_lookup(strlen(argv[1]),argv[1],0,&dev); + if (sts & 1) { + if (dev->vcb != NULL) { + sts = dismount(dev->vcb); + } else { + sts = SS$_DEVNOTMOUNT; + } + } + if ((sts & 1) == 0) printf("%%DISMOUNT-E-STATUS Error: %d\n",sts); + return sts; +} + +char *mouquals[] = {"write",NULL}; + +unsigned domount(int argc,char *argv[],int qualc,char *qualv[]) +{ + char *dev = argv[1]; + char *lab = argv[2]; + int sts = 1,devices = 0; + char *devs[100],*labs[100]; + int options = checkquals(mouquals,qualc,qualv); + while (*lab != '\0') { + labs[devices++] = lab; + while (*lab != ',' && *lab != '\0') lab++; + if (*lab != '\0') { + *lab++ = '\0'; + } else { + break; + } + } + devices = 0; + while (*dev != '\0') { + devs[devices++] = dev; + while (*dev != ',' && *dev != '\0') dev++; + if (*dev != '\0') { + *dev++ = '\0'; + } else { + break; + } + } + if (devices > 0) { + unsigned i; + struct VCB *vcb; + sts = mount(options,devices,devs,labs,&vcb); + if (sts & 1) { + for (i = 0; i < vcb->devices; i++) + if (vcb->vcbdev[i].dev != NULL) + printf("%%MOUNT-I-MOUNTED, Volume %12.12s mounted on %s\n", + vcb->vcbdev[i].home.hm2$t_volname,vcb->vcbdev[i].dev->devnam); + } else { + printf("Mount failed with %d\n",sts); + } + } + return sts; +} + + +void directshow(void); +void phyio_show(void); + +/* statis: print some simple statistics */ + +unsigned statis(int argc,char *argv[],int qualc,char *qualv[]) +{ + printf("Statistics:-\n"); + directshow(); + cacheshow(); + phyio_show(); + return 1; +} + +/* dump: a simple debugging aid */ + +unsigned dump(int argc,char *argv[],int qualc,char *qualv[]) +{ + printf("Cache Dump:-\n"); + cachedump(); + return 1; +} +#endif + + +/* help: a routine to print a pre-prepared help text... */ + +unsigned help(int argc,char *argv[],int qualc,char *qualv[]) +{ + printf("\nODS2 v1.2\n"); + printf(" Please send problems/comments to Paulnank@au1.ibm.com\n"); + printf(" Commands are:\n"); + printf(" copy difference directory exit\n"); + printf(" mount show_default show_time search\n"); + printf(" set_default type\n"); + printf(" Example:-\n $ mount e:\n"); + printf(" $ search e:[vms$common.decc*...]*.h rms$_wld\n"); + printf(" $ set default e:[sys0.sysmgr]\n"); + printf(" $ copy *.com;-1 c:\\*.*\n"); + printf(" $ directory/file/size/date [-.sys*...].%%\n"); + printf(" $ exit\n"); + return 1; +} + + +/* informaion about the commands we know... */ + +struct CMDSET { + char *name; + unsigned (*proc) (int argc,char *argv[],int qualc,char *qualv[]); + int minlen; + int minargs; + int maxargs; + int maxquals; +} cmdset[] = { + { + "copy",copy,3,3,3,0 +}, + { + "delete",del,3,2,2,0 +}, + { + "difference",diff,3,3,3,0 +}, + { + "directory",dir,3,1,2,6 +}, + { + "exit",NULL,2,0,0,0 +}, + { + "help",help,2,1,1,0 +}, + { + "show",show,2,2,2,0 +}, + { + "search",search,3,3,3,0 +}, + { + "set",set,3,2,3,0 +}, +#ifndef VMSIO + { + "dismount",dodismount,3,2,2,0 +}, + { + "mount",domount,3,2,3,2 +}, + { + "statistics",statis,3,1,1,0 +}, + { + "dump",dump,3,1,1,0 +}, +#endif + { + "type",typ,3,2,2,0 +}, + { + NULL,NULL,0,0,0,0 +} +}; + + +/* cmdexecute: identify and execute a command */ + +int cmdexecute(int argc,char *argv[],int qualc,char *qualv[]) +{ + char *ptr = argv[0]; + struct CMDSET *cmd = cmdset; + unsigned cmdsiz = strlen(ptr); + while (*ptr != '\0') { + *ptr = tolower(*ptr); + ptr++; + } + while (cmd->name != NULL) { + if (cmdsiz >= cmd->minlen && cmdsiz <= strlen(cmd->name)) { + if (keycomp(argv[0],cmd->name)) { + if (cmd->proc == NULL) { + return 0; + } else { + if (argc < cmd->minargs || argc > cmd->maxargs) { + printf("%%ODS2-E-PARAMS, Incorrect number of command parameters\n"); + } else { + if (qualc > cmd->maxquals) { + printf("%%ODS2-E-QUALS, Too many command qualifiers\n"); + } else { + (*cmd->proc) (argc,argv,qualc,qualv); +#ifndef VMSIO + cacheflush(); +#endif + } + } + return 1; + } + } + } + cmd++; + } + printf("%%ODS2-E-ILLCMD, Illegal or ambiguous command '%s'\n",argv[0]); + return 1; +} + +/* cmdsplit: break a command line into its components */ + +int cmdsplit(char *str) +{ + int argc = 0,qualc = 0; + char *argv[32],*qualv[32]; + char *sp = str; + int i; + for (i = 0; i < 32; i++) argv[i] = qualv[i] = ""; + while (*sp != '\0') { + while (*sp == ' ') sp++; + if (*sp != '\0') { + if (*sp == '/') { + *sp++ = '\0'; + qualv[qualc++] = sp; + } else { + argv[argc++] = sp; + } + while (*sp != ' ' && *sp != '/' && *sp != '\0') sp++; + if (*sp == '\0') { + break; + } else { + if (*sp != '/') *sp++ = '\0'; + } + } + } + if (argc > 0) return cmdexecute(argc,argv,qualc,qualv); + return 1; +} + + +/* main: the simple mainline of this puppy... */ + +int main(int argc,char *argv[]) +{ + char str[2048]; + printf(" ODS2 v1.2\n"); + while (1) { + printf("$> "); + if (gets(str) == NULL) break; + if (strlen(str)) if ((cmdsplit(str) & 1) == 0) break; + } + return 1; +} diff --git a/extracters/ods2/phyio.h b/extracters/ods2/phyio.h new file mode 100644 index 0000000..8fc6663 --- /dev/null +++ b/extracters/ods2/phyio.h @@ -0,0 +1,44 @@ +/* Phy.h v1.2 Definition of Physical I/O routines */ + +/* + This is part of ODS2 written by Paul Nankervis, + email address: Paulnank@au1.ibm.com + + ODS2 is distributed freely for all members of the + VMS community to use. However all derived works + must maintain comments in their source to acknowledge + the contibution of the original author. +*/ + +/* To set up physical I/O for a new system a group of phyio + routines need to be set up. They are:- + phyio_show() which doesn't need to do anything - but + it would generally print some statistics + about the other phyio calls. + phyio_init() to prepare a device for use by future + read/write calls. The device name would usually + map to a local device - for example rra: to /dev/rra + on a Unix system. The call needs to return a handle + (channel, file handle, reference number...) for + future reference, and optionally some device + information. + phyio_read() will return a specified number of bytes into a + buffer from the start of a 512 byte block on the + device referred to by the handle. + phyio_write() will write a number of bytes out to a 512 byte block + address on a device. + +*/ + +#define PHYIO_READONLY 1 + +struct phyio_info { + unsigned status; + unsigned sectors; + unsigned sectorsize; +}; + +void phyio_show(void); +unsigned phyio_init(int devlen,char *devnam,unsigned *handle,struct phyio_info *info); +unsigned phyio_read(unsigned handle,unsigned block,unsigned length,char *buffer); +unsigned phyio_write(unsigned handle,unsigned block,unsigned length,char *buffer); diff --git a/extracters/ods2/phynt.c b/extracters/ods2/phynt.c new file mode 100644 index 0000000..ce57e12 --- /dev/null +++ b/extracters/ods2/phynt.c @@ -0,0 +1,517 @@ +/* PHYNT.C v1.2 Physical I/O module for Windows NT */ + +/* W95 code now included with code to automatically determine + if we are running under NT... + + W98 seems to have a performance problem where the + INT25 call are VERY slow!!! */ + + + +/* This version built and tested under Visual C++. To support + CD drives this version requires ASPI run-time support. For + SCSI drives probably any old ASPI library will do. But for + ATAPI drives on NT there are 'ASPI libraries and there are + ASPI libraries'. I have had success with an older version of + Adaptec's APSI (version 2,4,0,0) and with Symbios Logic + libraries. But I have NOT been able to make the latest + Adaptec routines work on NT! + Note: Windows 95 comes with APSI by default! */ + +#include +#include +#include +#include +#include +#include +#include + +#include "phyio.h" +#include "ssdef.h" + + +unsigned init_count = 0; /* Some counters so we can report */ +unsigned read_count = 0; /* How often we get called */ +unsigned write_count = 0; + +void phyio_show(void) +{ + printf("PHYIO_SHOW Initializations: %d Reads: %d Writes: %d\n", + init_count,read_count,write_count); +} + + +unsigned phyio_write(unsigned handle,unsigned block,unsigned length,char *buffer) +{ + write_count++; + return SS$_WRITLCK; /* Not implemented yet!! */ +} + + +/* This routine figures out whether this is an NT system or not... */ + +unsigned is_NT = 2; +OSVERSIONINFO sysver; + +void getsysversion() +{ + memset(&sysver,0,sizeof(OSVERSIONINFO)); + sysver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&sysver); + if (sysver.dwPlatformId == VER_PLATFORM_WIN32_NT) { + is_NT = 1; + } else { + is_NT = 0; + } +} + +/* + To read from CD APSI run-time support is required (wnaspi32.dll). + NT does not come with APSI support so you need to install it first. + (ASPI is also required for things like Digital Audio Extraction + and was origionally loaded on my machine to make MP3 audio files.) + One downside is that ASPI on NT does not have a way to match SCSI + adapters and units to a system device. So this program works by + finding the first CD like unit on the system and using it - that + may NOT be what you want if you have several CD drives! And finally + there are CD drives and there are CD drives. From what I can tell + many simply won't work with this (or other!) code. Naturally if + you find a better way please let me know... Paulnank@au1.ibm.com +*/ + +#if defined (USE_WNASPI) + +#include "wnaspi32.h" + +unsigned cd_initialized = 0; /* Flag for CD read to go... */ +unsigned cd_adaptor,cd_target; /* Adaptor & SCSI #'s */ +HANDLE ASPICompletion; /* Windows event for ASPI wait */ + + +/* Get ASPI ready and locate the first CD drive... */ + +unsigned cd_initialize() +{ + if (cd_initialized) { + printf("Can only support one (first) ASPI device\n"); + return 8; + } else { + DWORD ASPIStatus; + ASPIStatus = GetASPI32SupportInfo(); + if (HIBYTE(LOWORD(ASPIStatus)) == SS_COMP) { + BYTE NumAdapters; + SRB_GDEVBlock Ssrb; + Ssrb.SRB_Cmd = SC_GET_DEV_TYPE; + Ssrb.SRB_HaId = 0; + Ssrb.SRB_Flags = SRB_EVENT_NOTIFY; + Ssrb.SRB_Hdr_Rsvd = 0; + Ssrb.SRB_Target = 0; + Ssrb.SRB_Lun = 0; + NumAdapters = LOWORD(LOBYTE(ASPIStatus)); + for (cd_adaptor = 0; cd_adaptor < NumAdapters; cd_adaptor++) { + for (cd_target = 0; cd_target <= 7; cd_target++) { + Ssrb.SRB_HaId = cd_adaptor; + Ssrb.SRB_Target = cd_target; + ASPIStatus = SendASPI32Command(&Ssrb); + if (ASPIStatus == SS_COMP && Ssrb.SRB_DeviceType == 5) break; + } + if (cd_target <= 7) break; + } + if (cd_adaptor < NumAdapters) { + if ((ASPICompletion = CreateEvent(NULL,FALSE,FALSE,NULL)) == NULL) return 8; + cd_initialized = 1; + return 1; + } else { + printf("Could not find ASPI CD device\n"); + return 8; + } + } else { + printf("Could not initialize ASPI (%x)\n",ASPIStatus); + return 8; + } + } +} + + +/* Read a sector from CD using ASPI... */ + +unsigned cd_read(unsigned sector,char *buffer) +{ + DWORD ASPIEventStatus; + SRB_ExecSCSICmd Esrb; + Esrb.SRB_Cmd = SC_EXEC_SCSI_CMD; + Esrb.SRB_HaId = cd_adaptor; + Esrb.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY; + Esrb.SRB_Hdr_Rsvd = 0; + Esrb.SRB_Target = cd_target; + Esrb.SRB_Lun = 0; + Esrb.SRB_BufLen = 2352; + Esrb.SRB_BufPointer = buffer; + Esrb.SRB_SenseLen = 0; + Esrb.SRB_CDBLen = 10; + Esrb.SRB_PostProc = ASPICompletion; + Esrb.CDBByte[0] = 0x28; /* Build SCSI read command packet... */ + Esrb.CDBByte[1] = 0; + Esrb.CDBByte[2] = (sector >> 24); + Esrb.CDBByte[3] = (sector >> 16) & 0xff; + Esrb.CDBByte[4] = (sector >> 8) & 0xff; + Esrb.CDBByte[5] = sector & 0xff; + Esrb.CDBByte[6] = 0; + Esrb.CDBByte[7] = 0; + Esrb.CDBByte[8] = 1; + Esrb.CDBByte[9] = 0; + Esrb.CDBByte[10] = 0; + SendASPI32Command(&Esrb); /* Perform the read... */ + while (Esrb.SRB_Status == SS_PENDING) + ASPIEventStatus = WaitForSingleObject(ASPICompletion,INFINITE); + /* if (ASPIEventStatus == WAIT_OBJECT_0) */ResetEvent(ASPICompletion); + if (Esrb.SRB_Status != SS_COMP) return SS$_PARITY; + return 1; +} +#else /* !defined(USE_WNASPI) */ + +unsigned cd_initialize() +{ + return 1; +} + +unsigned cd_read(unsigned sector,char *buffer) +{ + return 0; +} + +#endif /* defined(USE_WNASPI) */ + + +/* Some NT definitions... */ + +/* #include "Ntddcdrm.h" */ +#define IOCTL_CDROM_BASE FILE_DEVICE_CD_ROM +#define IOCTL_CDROM_RAW_READ CTL_CODE(IOCTL_CDROM_BASE, 0x000F, METHOD_OUT_DIRECT, FILE_READ_ACCESS) +#define IOCTL_CDROM_GET_DRIVE_GEOMETRY CTL_CODE(IOCTL_CDROM_BASE, 0x0013, METHOD_BUFFERED, FILE_READ_ACCESS) + +/* NT Get disk or CD geometry... */ + +BOOL + GetDiskGeometry( + HANDLE hDisk, + DISK_GEOMETRY *dGeometry + ) +{ + DWORD ReturnedByteCount; + BOOL results = DeviceIoControl( + hDisk, + IOCTL_DISK_GET_DRIVE_GEOMETRY, + NULL, + 0, + dGeometry, + sizeof(*dGeometry), + &ReturnedByteCount, + NULL + ); + if (!results) results = DeviceIoControl( + hDisk, + IOCTL_CDROM_GET_DRIVE_GEOMETRY, + NULL, + 0, + dGeometry, + sizeof(*dGeometry), + &ReturnedByteCount, + NULL + ); + return results; +} + + +/* NT drive lock - we don't want any interference... */ + +BOOL + LockVolume( + HANDLE hDisk + ) +{ + DWORD ReturnedByteCount; + + return DeviceIoControl( + hDisk, + FSCTL_LOCK_VOLUME, + NULL, + 0, + NULL, + 0, + &ReturnedByteCount, + NULL + ); +} + + + +/* Windows 95 I/O definitions... */ + +#define VWIN32_DIOC_DOS_IOCTL 1 +#define VWIN32_DIOC_DOS_INT25 2 +#define VWIN32_DIOC_DOS_INT26 3 + +#pragma pack(1) +typedef struct _DIOC_REGISTERS { + DWORD reg_EBX; + DWORD reg_EDX; + DWORD reg_ECX; + DWORD reg_EAX; + DWORD reg_EDI; + DWORD reg_ESI; + DWORD reg_Flags; +} DIOC_REGISTERS; + +typedef struct _DPB { + unsigned int dpb_sector; + unsigned short dpb_count; + char *dpb_buffer; +} DPB; + +typedef struct _DEVICEPARAM { + char junk1[7]; + unsigned short sec_size; + char junk2[23]; +} DEVICEPARAM; + +#pragma pack() + + + + +/* Each device we talk to has a channel entry so that we can + remember its details... */ + +#define CHAN_MAX 32 +unsigned chan_count = 0; +struct CHANTAB { + HANDLE handle; /* File handle for device */ + char *IoBuffer; /* Pointer to a buffer for the device */ + unsigned sectorsize; /* Device sector size */ + unsigned last_sector; /* Last sector no read (still in buffer) */ + short device_type; /* Flag for 'normal' or ASPI I/O */ + short device_name; /* Drive letter (A, B, C, ...) */ +} chantab[CHAN_MAX]; + + + + +/* Initialize device by opening it, locking it and getting it ready.. */ + +unsigned phyio_init(int devlen,char *devnam,unsigned *chanptr,struct phyio_info *info) +{ + unsigned sts = 1; + unsigned chan = chan_count; + if (is_NT > 1) getsysversion(); + if (chan < CHAN_MAX - 1 && devlen == 2 && + toupper(*devnam) >= 'A' && *(devnam + 1) == ':') { + HANDLE hDrive; + chantab[chan].device_name = toupper(*devnam); + chantab[chan].device_type = 0; + + /* NT stuff */ + + if (is_NT) { + char ntname[32]; + DISK_GEOMETRY Geometry; + sprintf(ntname,"\\\\.\\%s",devnam); + chantab[chan].handle = hDrive = CreateFileA( + ntname, + GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_NO_BUFFERING, + NULL + ); + if (hDrive == INVALID_HANDLE_VALUE) { + printf("Open %s failed %d\n",devnam,GetLastError()); + return SS$_NOSUCHDEV; + } + if (LockVolume(hDrive) == FALSE) { + printf("LockVolume %s failed %d\n",devnam,GetLastError()); + return 72; + } + if (!GetDiskGeometry(hDrive,&Geometry)) { + printf("GetDiskGeometry %s failed %d\n",devnam,GetLastError()); + return 80; + } + /* If this is a 2048 byte sector device past C treat it as a CD... */ + + chantab[chan].device_type = 0; + if (Geometry.BytesPerSector == 2048 && toupper(*devnam) > 'C') { + sts = cd_initialize(); + if ((sts & 1) == 0) return sts; + chantab[chan].device_type = 1; + } + chantab[chan].sectorsize = Geometry.BytesPerSector; + info->sectors = (unsigned)(Geometry.Cylinders.QuadPart * Geometry.TracksPerCylinder * + Geometry.SectorsPerTrack); + + } else { + +#if defined(USE_WIN95) + /* W95 stuff */ + + + if (chantab[chan].device_name > 'C') { /* Assume above C are CDs.. */ + sts = cd_initialize(); + if ((sts & 1) == 0) return sts; + chantab[chan].device_type = 1; + chantab[chan].sectorsize = 2048; + } else { + DIOC_REGISTERS reg; + DEVICEPARAM deviceparam; + BOOL fResult; + DWORD cb; + chantab[chan].handle = hDrive = CreateFileA( + "\\\\.\\vwin32", + 0,0, + NULL, + 0, + FILE_FLAG_DELETE_ON_CLOSE, + NULL); + if (hDrive == INVALID_HANDLE_VALUE) { + printf("Open %s failed %d\n",devnam,GetLastError()); + return SS$_NOSUCHDEV; + } + reg.reg_EAX = 0x440d; + reg.reg_EBX = chantab[chan].device_name - 'A' + 1; + reg.reg_ECX = 0x084a; /* Lock volume */ + reg.reg_EDX = 0; + reg.reg_Flags = 0x0000; /* Permission */ + + fResult = DeviceIoControl(hDrive, + VWIN32_DIOC_DOS_IOCTL, + ®,sizeof(reg), + ®,sizeof(reg), + &cb,0); + + if (!fResult || (reg.reg_Flags & 0x0001)) { + printf("Volume lock failed (%d)\n",GetLastError()); + return SS$_DEVNOTALLOC; + } + reg.reg_EAX = 0x440d; + reg.reg_EBX = chantab[chan].device_name - 'A' + 1; + reg.reg_ECX = 0x0860; /* Get device parameters */ + reg.reg_EDX = (DWORD) & deviceparam; + reg.reg_Flags = 0x0001; /* set carry flag */ + + fResult = DeviceIoControl(hDrive, + VWIN32_DIOC_DOS_IOCTL, + ®,sizeof(reg), + ®,sizeof(reg), + &cb,0); + + if (!fResult || (reg.reg_Flags & 0x0001)) { + printf("Volume get parameters failed (%d)\n",GetLastError()); + return 8; + } + chantab[chan].sectorsize = deviceparam.sec_size; + } + info->sectors = 0; +#endif /* defined(USE_WIN95) */ + } + + chantab[chan].IoBuffer = VirtualAlloc(NULL, + chantab[chan].sectorsize + 304,MEM_COMMIT,PAGE_READWRITE); + chantab[chan].last_sector = 1000; + *chanptr = chan_count++; + info->status = 0; + info->sectorsize = chantab[chan].sectorsize; + init_count++; + return 1; + } else { + return SS$_IVCHAN; + } +} + + + + +/* Read a physical sector... */ + +unsigned phy_getsect(unsigned chan,unsigned sector,char **buffptr) +{ + register unsigned sts = 1; + if (sector != chantab[chan].last_sector) { + if (chantab[chan].device_type) { + sts = cd_read(sector,chantab[chan].IoBuffer); + } else { + if (is_NT) { + DWORD BytesRead = -1; /* NT Bytes read */ + SetFilePointer(chantab[chan].handle, + sector * chantab[chan].sectorsize,0,FILE_BEGIN); + if (!ReadFile(chantab[chan].handle,chantab[chan].IoBuffer, + chantab[chan].sectorsize,&BytesRead,NULL)) sts = SS$_PARITY; + } else { + DIOC_REGISTERS reg; /* W95 DIOC registers */ + DPB dpb; + BOOL fResult; + DWORD cb = 0; + dpb.dpb_sector = sector; /* sector number */ + dpb.dpb_count = 1; /* sector count */ + dpb.dpb_buffer = chantab[chan].IoBuffer; /* sector buffer */ + reg.reg_EAX = chantab[chan].device_name - 'A'; /* drive */ + reg.reg_EBX = (DWORD) & dpb; /* parameter block */ + reg.reg_ECX = -1; /* use dpb */ + reg.reg_EDX = 0;/* sector num */ + reg.reg_EDI = 0; + reg.reg_ESI = 0; + reg.reg_Flags = 0x0001; /* set carry flag */ + fResult = DeviceIoControl(chantab[chan].handle, + VWIN32_DIOC_DOS_INT25, + ®,sizeof(reg), + ®,sizeof(reg), + &cb,0); + if (!fResult || (reg.reg_Flags & 0x0001)) { + printf("Sector %d read failed %d\n",sector,GetLastError()); + sts = SS$_PARITY; + } + } + } + } + if (sts & 1) { + chantab[chan].last_sector = sector; + *buffptr = chantab[chan].IoBuffer; + } + return sts; +} + + + + +/* Handle an I/O request ... need to read the approriate sectors to + complete the request... */ + +unsigned phyio_read(unsigned chan,unsigned block,unsigned length,char *buffer) +{ + register unsigned sts = 1; + + if (chan < chan_count) { + register unsigned sectorsize = chantab[chan].sectorsize; + register unsigned sectno = block / (sectorsize / 512); + register unsigned offset = (block - sectno * (sectorsize / 512)) * 512; + while (length > 0) { + register unsigned transfer; + char *sectbuff; + if (((sts = phy_getsect(chan,sectno,§buff)) & 1) == 0) break; + transfer = sectorsize - offset; + if (transfer > length) transfer = length; + memcpy(buffer,sectbuff + offset,transfer); + buffer += transfer; + length -= transfer; + sectno++; + offset = 0; + } + } else { + sts = SS$_IVCHAN; + } + if (sts & 1) { + read_count++; + } else { + printf("PHYIO Error %d Block %d Length %d\n",sts,block,length); + } + return sts; +} diff --git a/extracters/ods2/phyos2.c b/extracters/ods2/phyos2.c new file mode 100644 index 0000000..8840018 --- /dev/null +++ b/extracters/ods2/phyos2.c @@ -0,0 +1,210 @@ +/* PHYOS2.C v1.2 Physical I/O module for OS2 */ + +/* This version implemented to read from Floppy or CD by + guessing that A: or B: will be a floppy and anything + else is probably a CD? */ + + +#include +#include +#include +#define INCL_DOS +#define INCL_DOSDEVIOCTL +#define INCL_NOPMAPI +#include +#include "phyio.h" +#include "ssdef.h" + + + +unsigned init_count = 0; +unsigned read_count = 0; +unsigned write_count = 0; + +void phyio_show(void) +{ + printf("PHYIO_SHOW Initializations: %d Reads: %d Writes: %d\n", + init_count,read_count,write_count); +} + + +#pragma pack(1) +/*------------------------------------------------* + * Cat 0x80, Func 0x72: Read Long * + *------------------------------------------------*/ +struct ReadLong { + ULONG ID_code; + UCHAR address_mode; + USHORT transfer_count; + ULONG start_sector; + UCHAR reserved; + UCHAR interleave_size; + UCHAR interleave_skip_factor; +}; +#pragma pack() + +#define SECTORSIZE 2048 +struct ReadLong rl = { + 0x31304443L, /* "CD01" */ + 0, /* Address mode */ + 1, /* Transfer count */ + 0, /* Start Sector */ + 0, /* Reserved */ + 0, /* Interleave size */ + 0/* Skip factor */ +}; + +#define HANDLE_MAX 32 +int hand_count = 0; +struct HANDLE { + HFILE hand_hfile; + int hand_drive; +} handle[HANDLE_MAX]; + +unsigned phyio_init(int devlen,char *devnam,unsigned *hand,struct phyio_info *info) +{ + if (hand_count < HANDLE_MAX - 1) { + ULONG usAction; + ULONG open_mode; + ULONG bCmd; + ULONG stat; + char device[40]; + memcpy(device,devnam,devlen); + device[devlen] = '\0'; + handle[hand_count].hand_drive = toupper(*device); + open_mode = OPEN_FLAGS_DASD | OPEN_SHARE_DENYREADWRITE + | OPEN_FLAGS_WRITE_THROUGH | OPEN_FLAGS_FAIL_ON_ERROR + | OPEN_FLAGS_NOINHERIT | OPEN_ACCESS_READWRITE; + stat = DosOpen(device, /* filename to open */ + &handle[hand_count].hand_hfile, + /* address of file handle */ + &usAction, + /* address to store action taken */ + 0L, + /* size of new file */ + FILE_NORMAL, + /* file's attribute */ + FILE_OPEN, + /* action to take if file exists */ + open_mode, + /* file's open mode */ + 0L); + /* Reserved */ + if (stat) { + switch (stat) { + case 15: + printf("Drive %s is invalid.\n",device); + break; + case 21: + printf("Drive %s is not ready.\n",device); + break; + case 32: + printf("Drive %s is currently locked by another process.\n",device); + break; + case 65: + printf("Drive %s is a network drive.\n",device); + break; + default: + printf("error %d opening drive %s\n",stat,device); + } + return SS$_PARITY; + } + bCmd = 0; + stat = DosDevIOCtl(handle[hand_count].hand_hfile,IOCTL_DISK,DSK_LOCKDRIVE,&bCmd,1,NULL,NULL,0,NULL); + if (stat) { + printf("Error %d locking drive\n",stat); + return SS$_DEVNOTALLOC; + } + if (handle[hand_count].hand_drive > 'C') { + info->status = PHYIO_READONLY; + } else { + info->status = 0; + } + *hand = hand_count++; + init_count++; + return 1; + } else { + return SS$_IVCHAN; + } +} + + +unsigned phy_getsect(HFILE hfile,unsigned sector,char *buffer) +{ + ULONG ulPinout,ulDinout; + ULONG stat; + char rawsect[SECTORSIZE + 304]; + ulPinout = sizeof(rl); + ulDinout = sizeof(rawsect); + rl.start_sector = sector; + stat = DosDevIOCtl(hfile, + IOCTL_CDROMDISK, + CDROMDISK_READLONG, + &rl,sizeof(rl),&ulPinout, + rawsect,sizeof(rawsect),&ulDinout); + if (stat) { + printf("sys%04u: CDROMDISK_READLONG error\n",stat); + return SS$_PARITY; + } + memcpy(buffer,rawsect + 16,SECTORSIZE); + return 1; +} + + + + + +unsigned phyio_read(unsigned handno,unsigned block,unsigned length,char *buffer) +{ + register unsigned sts = 1; +#ifdef DEBUG + printf("PHYIO_READ block %d length %d\n",block,length); +#endif + if (handno >= hand_count) { + sts = SS$_IVCHAN; + } else { + if (handle[handno].hand_drive > 'C') { + register unsigned sect = block * 512 / SECTORSIZE; + register unsigned offset = (block - sect * SECTORSIZE / 512) * 512; + while (length > 0) { + register unsigned transfer; + if (offset == 0 && length >= SECTORSIZE) { + transfer = SECTORSIZE; + if (((sts = phy_getsect(handle[handno].hand_hfile,sect,buffer)) & 1) == 0) break; + } else { + char sector[SECTORSIZE]; + if (((sts = phy_getsect(handle[handno].hand_hfile,sect,sector)) & 1) == 0) break; + transfer = SECTORSIZE - offset; + if (transfer > length) transfer = length; + memcpy(buffer,sector + offset,transfer); + } + buffer += transfer; + length -= transfer; + sect++; + offset = 0; + } + } else { + USHORT rc; + ULONG oldpos,lenread; + sts = SS$_PARITY; + rc = DosSetFilePtr(handle[handno].hand_hfile,block * 512,0,&oldpos); + if (rc == 0) { + rc = DosRead(handle[handno].hand_hfile,buffer,length,&lenread); + if (rc == 0 && lenread == length) sts = 1; + } + } + } + if (sts & 1) { + read_count++; + } else { + printf("PHYOS2 Error %d Block %d Length %d\n",sts,block,length); + } + return sts; +} + + +unsigned phyio_write(unsigned handle,unsigned block,unsigned length,char *buffer) +{ + write_count++; + return SS$_WRITLCK; +} diff --git a/extracters/ods2/phyvms.c b/extracters/ods2/phyvms.c new file mode 100644 index 0000000..e4340cc --- /dev/null +++ b/extracters/ods2/phyvms.c @@ -0,0 +1,87 @@ +/* PHYVMS.C v1.2 Physical I/O module for VMS */ + +/* + This is part of ODS2 written by Paul Nankervis, + email address: Paulnank@au1.ibm.com + + ODS2 is distributed freely for all members of the + VMS community to use. However all derived works + must maintain comments in their source to acknowledge + the contibution of the original author. +*/ + +/* How come VMS is so much easier to do physical I/O on than + those other ^%$@*! systems? I can't believe that they have + different command sets for different device types, and can + even have different command sets depending on what mode they + are called from! Sigh. */ + + +#include +#include +#include +#include +#include + +#ifdef __GNUC__ +unsigned sys$assign(); +unsigned sys$qiow(); +unsigned sys$dassgn(); +#else +#include +#endif + +#include "phyio.h" + +#define chk(sts) {register chksts; if (((chksts = sts) & 1) == 0) lib$stop(chksts);} + +unsigned init_count = 0; +unsigned read_count = 0; +unsigned write_count = 0; + +void phyio_show(void) +{ + printf("PHYIO_SHOW Initializations: %d Reads: %d Writes: %d\n", + init_count,read_count,write_count); +} + + +unsigned phyio_init(int devlen,char *devnam,unsigned *handle,struct phyio_info *info) +{ + struct dsc$descriptor devdsc; + devdsc.dsc$w_length = devlen; + devdsc.dsc$a_pointer = devnam; + init_count++; + info->status = 0; /* We don't know anything about this device! */ + info->sectors = 0; + info->sectorsize = 0; + *handle = 0; + return sys$assign(&devdsc,handle,0,0,0,0); +} + + +unsigned phyio_close(unsigned handle) +{ + return sys$dassgn(handle); +} + + +unsigned phyio_read(unsigned handle,unsigned block,unsigned length,char *buffer) +{ +#ifdef DEBUG + printf("Phyio read block: %d into %x (%d bytes)\n",block,buffer,length); +#endif + read_count++; + return sys$qiow(1,handle,IO$_READLBLK,NULL,0,0,buffer,length,block,0,0,0); +} + + +unsigned phyio_write(unsigned handle,unsigned block,unsigned length,char *buffer) +{ +#ifdef DEBUG + printf("Phyio write block: %d from %x (%d bytes)\n",block,buffer,length); +#endif + write_count++; + printf("Phyio write block: %d from %x (%d bytes)\n",block,buffer,length); + return sys$qiow(1,handle,IO$_WRITELBLK,NULL,0,0,buffer,length,block,0,0,0); +} diff --git a/extracters/ods2/rms.c b/extracters/ods2/rms.c new file mode 100644 index 0000000..38cc14d --- /dev/null +++ b/extracters/ods2/rms.c @@ -0,0 +1,1049 @@ +/* Rms.c v1.2 RMS components */ + +/* + This is part of ODS2 written by Paul Nankervis, + email address: Paulnank@au1.ibm.com + + ODS2 is distributed freely for all members of the + VMS community to use. However all derived works + must maintain comments in their source to acknowledge + the contibution of the original author. +*/ + +/* Boy some cleanups are needed here - especially for + error handling and deallocation of memory after errors.. + For now we have to settle for loosing memory left/right/center... + + This module implements file name parsing, file searches, + file opens, gets, etc... */ + + +#define DEBUGx x + +#include +#include +#include +#include +#include "descrip.h" +#include "ssdef.h" +#include "fibdef.h" + +#define RMS_INITIALIZE doit /* used by rms.h to create templates */ +#include "rms.h" +#include "access.h" +#include "direct.h" + + +/* Table of file name component delimeters... */ + +char char_delim[] = { +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, 0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0}; + + +/* Routine to find size of file name components */ + +unsigned name_delim(char *str,int len,int size[5]) +{ + register unsigned ch; + register char *curptr = str; + register char *endptr = curptr + len; + register char *begptr = curptr; + while (curptr < endptr) { + ch = (*curptr++ & 127); + if (char_delim[ch]) break; + } + if (curptr > begptr && ch == ':') { + size[0] = (curptr - begptr); + begptr = curptr; + while (curptr < endptr) { + ch = (*curptr++ & 127); + if (char_delim[ch]) break; + } + } else { + size[0] = 0; + } + if (ch == '[' || ch == '<') { + if (curptr != begptr + 1) return RMS$_FNM; + while (curptr < endptr) { + ch = (*curptr++ & 127); + if (char_delim[ch]) if (ch != '.') break; + } + if (curptr < begptr + 2 || (ch != ']' && ch != '>')) return RMS$_FNM; + size[1] = (curptr - begptr); + begptr = curptr; + while (curptr < endptr) { + ch = (*curptr++ & 127); + if (char_delim[ch]) break; + } + } else { + size[1] = 0; + } + if (curptr > begptr && char_delim[ch]) { + size[2] = (curptr - begptr) - 1; + begptr = curptr - 1; + } else { + size[2] = (curptr - begptr); + begptr = curptr; + } + if (curptr > begptr && ch == '.') { + while (curptr < endptr) { + ch = (*curptr++ & 127); + if (char_delim[ch]) break; + } + if (curptr > begptr && char_delim[ch]) { + size[3] = (curptr - begptr) - 1; + begptr = curptr - 1; + } else { + size[3] = (curptr - begptr); + begptr = curptr; + } + } else { + size[3] = 0; + } + if (curptr > begptr && (ch == ';' || ch == '.')) { + while (curptr < endptr) { + ch = (*curptr++ & 127); + if (char_delim[ch]) break; + } + size[4] = (curptr - begptr); + } else { + size[4] = 0; + } +#ifdef DEBUG + printf("Name delim %d %d %d %d %d\n",size[0],size[1],size[2],size[3],size[4]); +#endif + if (curptr >= endptr) { + return 1; + } else { + return RMS$_FNM; + } +} + + +/* Function to compare directory cache names - directory cache NOT IN USE */ + +int dircmp(unsigned keylen,void *key,void *node) +{ + register struct DIRCACHE *dirnode = (struct DIRCACHE *) node; + register int cmp = keylen - dirnode->dirlen; + if (cmp == 0) { + register unsigned len = keylen; + register char *keynam = (char *) key; + register char *dirnam = dirnode->dirnam; + while (len-- > 0) { + cmp = toupper(*keynam++) - toupper(*dirnam++); + if (cmp != 0) break; + } + } + return cmp; +} + + +/* Routine to find directory name in cache... NOT CURRENTLY IN USE!!! */ + +unsigned dircache(struct VCB *vcb,char *dirnam,int dirlen,struct fiddef *dirid) +{ + register struct DIRCACHE *dir; + if (dirlen < 1) { + dirid->fid$w_num = 4; + dirid->fid$w_seq = 4; + dirid->fid$b_rvn = 0; + dirid->fid$b_nmx = 0; + return 1; + } else { + unsigned create = 0; + dir = cachesearch((void *) &vcb->dircache,0,dirlen,dirnam,dircmp,&create); + if (dir != NULL) { + memcpy(dirid,&dir->dirid,sizeof(struct fiddef)); + return 1; + } + return 0; + } +} + + +/* For file context info we use WCCDIR and WCCFILE structures... + Each WCCFILE structure contains one WCCDIR structure for file + context. Each level of directory has an additional WCCDIR record. + For example DKA200:[PNANKERVIS.F11]RMS.C is loosley stored as:- + next next + WCCFILE --> WCCDIR --> WCCDIR + RMS.C; F11.DIR;1 PNANKERVIS.DIR;1 + + WCCFILE is pointed to by fab->fab$l_nam->nam$l_wcc and if a + file is open also by ifi_table[fab->fab$w_ifi] (so that close + can easily locate it). + + Most importantly WCCFILE contains a resulting filename field + which stores the resulting file spec. Each WCCDIR has a prelen + length to indicate how many characters in the specification + exist before the bit contributed by this WCCDIR. (ie to store + the device name and any previous directory name entries.) */ + + +#define STATUS_INIT 1 +#define STATUS_TMPDIR 2 +#define STATUS_WILDCARD 4 + +struct WCCDIR { + struct WCCDIR *wcd_next; + struct WCCDIR *wcd_prev; + int wcd_status; + int wcd_wcc; + int wcd_prelen; + unsigned short wcd_reslen; + struct dsc$descriptor wcd_serdsc; + struct fiddef wcd_dirid; + char wcd_sernam[1]; /* Must be last in structure */ +}; /* Directory context */ + + +#define STATUS_RECURSE 8 +#define STATUS_TMPWCC 16 +#define MAX_FILELEN 1024 + +struct WCCFILE { + struct FAB *wcf_fab; + struct VCB *wcf_vcb; + struct FCB *wcf_fcb; + int wcf_status; + struct fiddef wcf_fid; + char wcf_result[MAX_FILELEN]; + struct WCCDIR wcf_wcd; /* Must be last..... (dynamic length). */ +}; /* File context */ + + +/* Function to remove WCCFILE and WCCDIR structures when not required */ + +void cleanup_wcf(struct WCCFILE *wccfile) +{ + if (wccfile != NULL) { + struct WCCDIR *wcc = wccfile->wcf_wcd.wcd_next; + wccfile->wcf_wcd.wcd_next = NULL; + wccfile->wcf_wcd.wcd_prev = NULL; + /* should deaccess volume */ + free(wccfile); + while (wcc != NULL) { + struct WCCDIR *next = wcc->wcd_next; + wcc->wcd_next = NULL; + wcc->wcd_prev = NULL; + free(wcc); + wcc = next; + } + } +} + + +/* Function to perform an RMS search... */ + +unsigned do_search(struct FAB *fab,struct WCCFILE *wccfile) +{ + int sts; + struct fibdef fibblk; + struct WCCDIR *wcc; + struct dsc$descriptor fibdsc,resdsc; + struct NAM *nam = fab->fab$l_nam; + wcc = &wccfile->wcf_wcd; + if (fab->fab$w_ifi != 0) return RMS$_IFI; + + /* if first time through position at top directory... WCCDIR */ + + while ((wcc->wcd_status & STATUS_INIT) == 0 && wcc->wcd_next != NULL) { + wcc = wcc->wcd_next; + } + fibdsc.dsc$w_length = sizeof(struct fibdef); + fibdsc.dsc$a_pointer = (char *) &fibblk; + while (1) { + if ((wcc->wcd_status & STATUS_INIT) == 0 || wcc->wcd_wcc != 0) { + wcc->wcd_status |= STATUS_INIT; + resdsc.dsc$w_length = 256 - wcc->wcd_prelen; + resdsc.dsc$a_pointer = wccfile->wcf_result + wcc->wcd_prelen; + memcpy(&fibblk.fib$w_did_num,&wcc->wcd_dirid,sizeof(struct fiddef)); + fibblk.fib$w_nmctl = 0; /* FIB$M_WILD; */ + fibblk.fib$l_acctl = 0; + fibblk.fib$w_fid_num = 0; + fibblk.fib$w_fid_seq = 0; + fibblk.fib$b_fid_rvn = 0; + fibblk.fib$b_fid_nmx = 0; + fibblk.fib$l_wcc = wcc->wcd_wcc; +#ifdef DEBUG + wcc->wcd_sernam[wcc->wcd_serdsc.dsc$w_length] = '\0'; + wccfile->wcf_result[wcc->wcd_prelen + wcc->wcd_reslen] = '\0'; + printf("Ser: '%s' (%d,%d,%d) WCC: %d Prelen: %d '%s'\n",wcc->wcd_sernam, + fibblk.fib$w_did_num | (fibblk.fib$b_did_nmx << 16), + fibblk.fib$w_did_seq,fibblk.fib$b_did_rvn, + wcc->wcd_wcc,wcc->wcd_prelen,wccfile->wcf_result + wcc->wcd_prelen); +#endif + sts = direct(wccfile->wcf_vcb,&fibdsc,&wcc->wcd_serdsc,&wcc->wcd_reslen,&resdsc,0); + } else { + sts = SS$_NOMOREFILES; + } + if (sts & 1) { +#ifdef DEBUG + wccfile->wcf_result[wcc->wcd_prelen + wcc->wcd_reslen] = '\0'; + printf("Fnd: '%s' (%d,%d,%d) WCC: %d\n",wccfile->wcf_result + wcc->wcd_prelen, + fibblk.fib$w_fid_num | (fibblk.fib$b_fid_nmx << 16), + fibblk.fib$w_fid_seq,fibblk.fib$b_fid_rvn, + wcc->wcd_wcc); +#endif + wcc->wcd_wcc = fibblk.fib$l_wcc; + if (wcc->wcd_prev) {/* go down directory */ + if (wcc->wcd_prev->wcd_next != wcc) printf("wcd_PREV corruption\n"); + if (fibblk.fib$w_fid_num != 4 || fibblk.fib$b_fid_nmx != 0 || + wcc == &wccfile->wcf_wcd || + memcmp(wcc->wcd_sernam,"000000.",7) == 0) { + memcpy(&wcc->wcd_prev->wcd_dirid,&fibblk.fib$w_fid_num,sizeof(struct fiddef)); + if (wcc->wcd_next) wccfile->wcf_result[wcc->wcd_prelen - 1] = '.'; + wcc->wcd_prev->wcd_prelen = wcc->wcd_prelen + wcc->wcd_reslen - 5; + wcc = wcc->wcd_prev; /* go down one level */ + if (wcc->wcd_prev == NULL) wccfile->wcf_result[wcc->wcd_prelen - 1] = ']'; + } + } else { + if (nam != NULL) { + int fna_size[5]; + memcpy(&nam->nam$w_fid_num,&fibblk.fib$w_fid_num,sizeof(struct fiddef)); + nam->nam$b_rsl = wcc->wcd_prelen + wcc->wcd_reslen; + name_delim(wccfile->wcf_result,nam->nam$b_rsl,fna_size); + nam->nam$l_dev = nam->nam$l_rsa; + nam->nam$b_dev = fna_size[0]; + nam->nam$l_dir = nam->nam$l_dev + fna_size[0]; + nam->nam$b_dir = fna_size[1]; + nam->nam$l_name = nam->nam$l_dir + fna_size[1]; + nam->nam$b_name = fna_size[2]; + nam->nam$l_type = nam->nam$l_name + fna_size[2]; + nam->nam$b_type = fna_size[3]; + nam->nam$l_ver = nam->nam$l_type + fna_size[3]; + nam->nam$b_ver = fna_size[4]; + if (nam->nam$b_rsl <= nam->nam$b_rss) { + memcpy(nam->nam$l_rsa,wccfile->wcf_result,nam->nam$b_rsl); + } else { + return RMS$_RSS; + } + } + memcpy(&wccfile->wcf_fid,&fibblk.fib$w_fid_num,sizeof(struct fiddef)); + + return 1; + } + } else { +#ifdef DEBUG + printf("Err: %d\n",sts); +#endif + if (sts == SS$_BADIRECTORY) { + if (wcc->wcd_next != NULL) { + if (wcc->wcd_next->wcd_status & STATUS_INIT) sts = SS$_NOMOREFILES; + } + } + if (sts == SS$_NOMOREFILES) { + wcc->wcd_status &= ~STATUS_INIT; + wcc->wcd_wcc = 0; + wcc->wcd_reslen = 0; + if (wcc->wcd_status & STATUS_TMPDIR) { + struct WCCDIR *savwcc = wcc; + if (wcc->wcd_next != NULL) wcc->wcd_next->wcd_prev = wcc->wcd_prev; + if (wcc->wcd_prev != NULL) wcc->wcd_prev->wcd_next = wcc->wcd_next; + wcc = wcc->wcd_next; + memcpy(wccfile->wcf_result + wcc->wcd_prelen + wcc->wcd_reslen - 6,".DIR;1",6); + free(savwcc); + } else { + if ((wccfile->wcf_status & STATUS_RECURSE) && wcc->wcd_prev == NULL) { + struct WCCDIR *newwcc; + newwcc = (struct WCCDIR *) malloc(sizeof(struct WCCDIR) + 8); + newwcc->wcd_next = wcc->wcd_next; + newwcc->wcd_prev = wcc; + newwcc->wcd_wcc = 0; + newwcc->wcd_status = STATUS_TMPDIR; + newwcc->wcd_reslen = 0; + if (wcc->wcd_next != NULL) { + wcc->wcd_next->wcd_prev = newwcc; + } + wcc->wcd_next = newwcc; + memcpy(&newwcc->wcd_dirid,&wcc->wcd_dirid,sizeof(struct fiddef)); + newwcc->wcd_serdsc.dsc$w_length = 7; + newwcc->wcd_serdsc.dsc$a_pointer = newwcc->wcd_sernam; + memcpy(newwcc->wcd_sernam,"*.DIR;1",7); + newwcc->wcd_prelen = wcc->wcd_prelen; + wcc = newwcc; + + } else { + if (wcc->wcd_next != NULL) { +#ifdef DEBUG + if (wcc->wcd_next->wcd_prev != wcc) printf("wcd_NEXT corruption\n"); +#endif + wcc = wcc->wcd_next; /* backup one level */ + memcpy(wccfile->wcf_result + wcc->wcd_prelen + wcc->wcd_reslen - 6,".DIR;1",6); + } else { + sts = RMS$_NMF; + break; /* giveup */ + } + } + } + } else { + if (sts == SS$_NOSUCHFILE) { + if (wcc->wcd_prev) { + sts = RMS$_DNF; + } else { + sts = RMS$_FNF; + } + } + break; /* error - abort! */ + } + } + } + cleanup_wcf(wccfile); + if (nam != NULL) nam->nam$l_wcc = 0; + fab->fab$w_ifi = 0; /* must dealloc memory blocks! */ + return sts; +} + + +/* External entry for search function... */ + +unsigned sys_search(struct FAB *fab) +{ + struct NAM *nam = fab->fab$l_nam; + struct WCCFILE *wccfile; + if (nam == NULL) return RMS$_NAM; + wccfile = (struct WCCFILE *) nam->nam$l_wcc; + if (wccfile == NULL) return RMS$_WCC; + return do_search(fab,wccfile); +} + + + +#define DEFAULT_SIZE 120 +char default_buffer[DEFAULT_SIZE]; +char *default_name = "DKA200:[000000].;"; +int default_size[] = {7,8,0,1,1}; + + +/* Function to perform RMS parse.... */ + +unsigned do_parse(struct FAB *fab,struct WCCFILE **wccret) +{ + struct WCCFILE *wccfile; + char *fna = fab->fab$l_fna; + char *dna = fab->fab$l_dna; + struct NAM *nam = fab->fab$l_nam; + int sts; + int fna_size[5] = {0, 0, 0, 0, 0},dna_size[5] = {0, 0, 0, 0, 0}; + if (fab->fab$w_ifi != 0) return RMS$_IFI; + if (nam != NULL) if (nam->nam$l_wcc == 0) { + cleanup_wcf((struct WCCFILE *) nam->nam$l_wcc); + nam->nam$l_wcc = 0; + } + /* Break up file specifications... */ + + sts = name_delim(fna,fab->fab$b_fns,fna_size); + if ((sts & 1) == 0) return sts; + if (dna) { + sts = name_delim(dna,fab->fab$b_dns,dna_size); + if ((sts & 1) == 0) return sts; + } + /* Make WCCFILE entry for rest of processing */ + + { + wccfile = (struct WCCFILE *) malloc(sizeof(struct WCCFILE) + 256); + if (wccfile == NULL) return SS$_INSFMEM; + wccfile->wcf_fab = fab; + wccfile->wcf_vcb = NULL; + wccfile->wcf_fcb = NULL; + wccfile->wcf_status = 0; + wccfile->wcf_wcd.wcd_status = 0; + } + + /* Combine file specifications */ + + { + int field,ess = MAX_FILELEN; + char *esa,*def = default_name; + esa = wccfile->wcf_result; + for (field = 0; field < 5; field++) { + char *src; + int len = fna_size[field]; + if (len > 0) { + src = fna; + } else { + len = dna_size[field]; + if (len > 0) { + src = dna; + } else { + len = default_size[field]; + src = def; + } + } + fna += fna_size[field]; + if (field == 1) { + int dirlen = len; + if (len < 3) { + dirlen = len = default_size[field]; + src = def; + } else { + char ch1 = *(src + 1); + char ch2 = *(src + 2); + if (ch1 == '.' || (ch1 == '-' && + (ch2 == '-' || ch2 == '.' || ch2 == ']'))) { + char *dir = def; + int count = default_size[1] - 1; + len--; + src++; + while (len >= 2 && *src == '-') { + len--; + src++; + if (count < 2 || (count == 7 && + memcmp(dir,"[000000",7) == 0)) return RMS$_DIR; + while (count > 1) { + if (dir[--count] == '.') break; + } + } + if (count < 2 && len < 2) { + src = "[000000]"; + dirlen = len = 8; + } else { + if (*src != '.' && *src != ']') return RMS$_DIR; + if (*src == '.' && count < 2) { + src++; + len--; + } + dirlen = len + count; + if ((ess -= count) < 0) return RMS$_ESS; + memcpy(esa,dir,count); + esa += count; + } + } + } + fna_size[field] = dirlen; + } else { + fna_size[field] = len; + } + dna += dna_size[field]; + def += default_size[field]; + if ((ess -= len) < 0) return RMS$_ESS; + while (len-- > 0) { + register char ch; + *esa++ = ch = *src++; + if (ch == '*' || ch == '%') + wccfile->wcf_status |= STATUS_WILDCARD; + } + } + /* Pass back results... */ + if (nam) { + nam->nam$l_dev = nam->nam$l_esa; + nam->nam$b_dev = fna_size[0]; + nam->nam$l_dir = nam->nam$l_dev + fna_size[0]; + nam->nam$b_dir = fna_size[1]; + nam->nam$l_name = nam->nam$l_dir + fna_size[1]; + nam->nam$b_name = fna_size[2]; + nam->nam$l_type = nam->nam$l_name + fna_size[2]; + nam->nam$b_type = fna_size[3]; + nam->nam$l_ver = nam->nam$l_type + fna_size[3]; + nam->nam$b_ver = fna_size[4]; + nam->nam$b_esl = esa - wccfile->wcf_result; + nam->nam$l_fnb = 0; + if (wccfile->wcf_status & STATUS_WILDCARD) nam->nam$l_fnb = NAM$M_WILDCARD; + if (nam->nam$b_esl <= nam->nam$b_ess) { + memcpy(nam->nam$l_esa,wccfile->wcf_result,nam->nam$b_esl); + } else { + return RMS$_ESS; + } + } + } + sts = 1; + if (nam != NULL) if (nam->nam$b_nop & NAM$M_SYNCHK) sts = 0; + + /* Now build up WCC structures as required */ + + if (sts) { + int dirlen,dirsiz; + char *dirnam; + struct WCCDIR *wcc; + struct DEV *dev; + sts = device_lookup(fna_size[0],wccfile->wcf_result,0,&dev); + if ((sts & 1) == 0) return sts; + if ((wccfile->wcf_vcb = dev->vcb) == NULL) return SS$_DEVNOTMOUNT; + wcc = &wccfile->wcf_wcd; + wcc->wcd_prev = NULL; + wcc->wcd_next = NULL; + + + + /* find directory name - chop off ... if found */ + + dirnam = wccfile->wcf_result + fna_size[0] + 1; + dirlen = fna_size[1] - 2; /* Don't include [] */ + if (dirlen >= 3) { + if (memcmp(dirnam + dirlen - 3,"...",3) == 0) { + wccfile->wcf_status |= STATUS_RECURSE; + dirlen -= 3; + wccfile->wcf_status |= STATUS_WILDCARD; + } + } + /* see if we can find directory in cache... */ + + dirsiz = dirlen; + do { + char *dirend = dirnam + dirsiz; + if (dircache(wccfile->wcf_vcb,dirnam,dirsiz,&wcc->wcd_dirid)) break; + while (dirsiz > 0) { + dirsiz--; + if (char_delim[*--dirend & 127]) break; + } + } while (1); + + + /* Create directory wcc blocks for what's left ... */ + + while (dirsiz < dirlen) { + int seglen = 0; + char *dirptr = dirnam + dirsiz; + struct WCCDIR *wcd; + do { + if (char_delim[*dirptr++ & 127]) break; + seglen++; + } while (dirsiz + seglen < dirlen); + wcd = (struct WCCDIR *) malloc(sizeof(struct WCCDIR) + seglen + 8); + wcd->wcd_wcc = 0; + wcd->wcd_status = 0; + wcd->wcd_prelen = 0; + wcd->wcd_reslen = 0; + memcpy(wcd->wcd_sernam,dirnam + dirsiz,seglen); + memcpy(wcd->wcd_sernam + seglen,".DIR;1",7); + wcd->wcd_serdsc.dsc$w_length = seglen + 6; + wcd->wcd_serdsc.dsc$a_pointer = wcd->wcd_sernam; + wcd->wcd_prev = wcc; + wcd->wcd_next = wcc->wcd_next; + if (wcc->wcd_next != NULL) wcc->wcd_next->wcd_prev = wcd; + wcc->wcd_next = wcd; + wcd->wcd_prelen = fna_size[0] + dirsiz + 1; /* Include [. */ + memcpy(&wcd->wcd_dirid,&wccfile->wcf_wcd.wcd_dirid,sizeof(struct fiddef)); + dirsiz += seglen + 1; + } + wcc->wcd_wcc = 0; + wcc->wcd_status = 0; + wcc->wcd_reslen = 0; + wcc->wcd_serdsc.dsc$w_length = fna_size[2] + fna_size[3] + fna_size[4]; + wcc->wcd_serdsc.dsc$a_pointer = wcc->wcd_sernam; + memcpy(wcc->wcd_sernam,wccfile->wcf_result + fna_size[0] + fna_size[1], + wcc->wcd_serdsc.dsc$w_length); +#ifdef DEBUG + wcc->wcd_sernam[wcc->wcd_serdsc.dsc$w_length] = '\0'; + printf("Parse spec is %s\n",wccfile->wcf_wcd.wcd_sernam); + for (dirsiz = 0; dirsiz < 5; dirsiz++) printf(" %d",fna_size[dirsiz]); + printf("\n"); +#endif + } + if (wccret != NULL) *wccret = wccfile; + if (nam != NULL) nam->nam$l_wcc = (int) wccfile; + return SS$_NORMAL; +} + + +/* External entry for parse function... */ + +unsigned sys_parse(struct FAB *fab) +{ + struct NAM *nam = fab->fab$l_nam; + if (nam == NULL) return RMS$_NAM; + return do_parse(fab,NULL); +} + + +/* Function to set default directory (heck we can sneak in the device...) */ + +unsigned sys_setddir(struct dsc$descriptor *newdir,unsigned short *oldlen, + struct dsc$descriptor *olddir) +{ + unsigned sts = 1; + if (oldlen != NULL) { + int retlen = default_size[0] + default_size[1]; + if (retlen > olddir->dsc$w_length) retlen = olddir->dsc$w_length; + *oldlen = retlen; + memcpy(olddir->dsc$a_pointer,default_name,retlen); + } + if (newdir != NULL) { + struct FAB fab = cc$rms_fab; + struct NAM nam = cc$rms_nam; + fab.fab$l_nam = &nam; + nam.nam$b_nop |= NAM$M_SYNCHK; + nam.nam$b_ess = DEFAULT_SIZE; + nam.nam$l_esa = default_buffer; + fab.fab$b_fns = newdir->dsc$w_length; + fab.fab$l_fna = newdir->dsc$a_pointer; + sts = sys_parse(&fab); + if (sts & 1) { + if (nam.nam$b_name + nam.nam$b_type + nam.nam$b_ver > 2) return RMS$_DIR; + if (nam.nam$l_fnb & NAM$M_WILDCARD) return RMS$_WLD; + default_name = default_buffer; + default_size[0] = nam.nam$b_dev; + default_size[1] = nam.nam$b_dir; + memcpy(default_name + nam.nam$b_dev + nam.nam$b_dir,".;",3); + } + } + return sts; +} + + +/* This version of connect only resets record pointer */ + +unsigned sys_connect(struct RAB *rab) +{ + rab->rab$w_rfa[0] = 0; + rab->rab$w_rfa[1] = 0; + rab->rab$w_rfa[2] = 0; + rab->rab$w_rsz = 0; + if (rab->rab$l_fab->fab$b_org == FAB$C_SEQ) { + return 1; + } else { + return SS$_NOTINSTALL; + } +} + + +/* Disconnect is even more boring */ + +unsigned sys_disconnect(struct RAB *rab) +{ + return 1; +} + + + +#define IFI_MAX 10 +struct WCCFILE *ifi_table[] = { + NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL +}; + + +/* get for sequential files */ + +unsigned sys_get(struct RAB *rab) +{ + char delim,*buffer,*output; + unsigned cpylen,reclen,block,blocks,offset,eofblk; + unsigned endflg,rfm,sts; + struct VIOC *vioc; + struct FCB *fcb = ifi_table[rab->rab$l_fab->fab$w_ifi]->wcf_fcb; + + rfm = rab->rab$l_fab->fab$b_rfm; + if (rfm == FAB$C_STM || rfm == FAB$C_STMCR || rfm == FAB$C_STMLF) { + delim = 1; + if (rfm == FAB$C_STMLF) { + delim = '\n'; + } else { + if (rfm == FAB$C_STMCR) delim = '\r'; + } + reclen = rab->rab$w_usz; + } else { + delim = 0; + if (rfm == FAB$C_FIX) { + reclen = rab->rab$l_fab->fab$w_mrs; + } + } + + offset = rab->rab$w_rfa[2] + rab->rab$w_rsz; + block = (rab->rab$w_rfa[1] << 16) + rab->rab$w_rfa[0]; + if (block == 0 && offset == 0) { + block = 1; + } else { + if (rab->rab$b_rac != RAB$C_RFA) { + if (delim) { + offset++; + } else { + if (rfm == FAB$C_VAR) { + offset += 2; + } else { + if (rfm == FAB$C_VFC) offset += 2 + rab->rab$l_fab->fab$b_fsz; + } + if (offset & 1) offset++; + if (rab->rab$l_fab->fab$b_rat & FAB$M_BLK) offset = (offset + 511) / 512 * 512; + } + block += offset / 512; + } + } + rab->rab$w_rfa[0] = block & 0xffff; + rab->rab$w_rfa[1] = block >> 16; + rab->rab$w_rfa[2] = offset = offset % 512; + + + eofblk = swapw(fcb->head->fh2$w_recattr.fat$l_efblk); + if (block > eofblk || (block == eofblk && + offset >= fcb->head->fh2$w_recattr.fat$w_ffbyte)) return RMS$_EOF; + sts = accesschunk(fcb,block,&vioc,&buffer,&blocks,0,NULL); + if ((sts & 1) == 0) return sts; + + if (rfm == FAB$C_VAR || rfm == FAB$C_VFC) { + unsigned short *lenptr = (unsigned short *) (buffer + offset); + reclen = *lenptr; + offset += 2; + } +#ifdef DEBUG + printf("Block %d Offset %d Reclen %d Eofblk %d\n",block,offset,reclen,eofblk); +#endif + + if (reclen > rab->rab$w_usz) { + sts = deaccesschunk(vioc,0,0); + return RMS$_RTB; + } + endflg = 0; + if (block + reclen / 512 >= eofblk) { + unsigned remaining = (eofblk - block) * 512 - offset + + fcb->head->fh2$w_recattr.fat$w_ffbyte; + if (remaining < reclen) { + reclen = remaining; + endflg = 1; + } + } + cpylen = 0; + output = rab->rab$l_ubf; + while (cpylen < reclen) { + unsigned seglen = blocks * 512 - offset; + if (seglen > reclen - cpylen) seglen = reclen - cpylen; + if (delim) { + char *inptr = buffer + offset; + if (delim != 1) { + while (seglen-- > 0) { + char ch = *inptr++; + if (ch == delim) { + reclen = cpylen; + break; + } + if (cpylen++ < reclen) { + *output++ = ch; + } else { + sts = RMS$_RTB; + reclen = cpylen; + break; + } + } + } else { + while (seglen-- > 0) { + char ch = *inptr++; + if (ch != 0 || cpylen > 0) { + if (ch == '\f' || ch == '\v' || ch == '\n' || ch == '\r') { + reclen = cpylen; + } else { + if (cpylen++ < reclen) { + *output++ = ch; + } else { + sts = RMS$_RTB; + reclen = cpylen; + break; + } + } + } + } + } + if (cpylen == reclen && endflg) break; + } else { + if (rfm == FAB$C_VFC) { + unsigned fsz = rab->rab$l_fab->fab$b_fsz; + if (fsz > seglen) fsz = seglen; + if (cpylen < fsz) { + fsz = fsz - cpylen; + if (rab->rab$l_rhb) memcpy(rab->rab$l_rhb + cpylen,buffer + offset,fsz); + cpylen += fsz; + offset += fsz; + seglen -= fsz; + } + } + memcpy(output,buffer + offset,seglen); + output += seglen; + cpylen += seglen; + } + if (cpylen < reclen) { + sts = deaccesschunk(vioc,0,0); + block += blocks; + if (block > eofblk) return RMS$_EOF; + sts = accesschunk(fcb,block,&vioc,&buffer,&blocks,0,NULL); + if ((sts & 1) == 0) return sts; + offset = 0; + } + } + if (rfm == FAB$C_VFC) { + rab->rab$w_rsz = cpylen - rab->rab$l_fab->fab$b_fsz;; + } else { + rab->rab$w_rsz = cpylen; + } + deaccesschunk(vioc,0,1); + return sts; +} + + +/* display to fill fab & xabs with info from the file header... */ + +unsigned sys_display(struct FAB *fab) +{ + struct XABDAT *xab = fab->fab$l_xab; + + struct HEAD *head = ifi_table[fab->fab$w_ifi]->wcf_fcb->head; + unsigned short *pp = (unsigned short *) head; + struct IDENT *id = (struct IDENT *) (pp + head->fh2$b_idoffset); + int ifi_no = fab->fab$w_ifi; + if (ifi_no == 0 || ifi_no >= IFI_MAX) return RMS$_IFI; + fab->fab$l_alq = swapw(head->fh2$w_recattr.fat$l_hiblk); + fab->fab$b_bks = head->fh2$w_recattr.fat$b_bktsize; + fab->fab$w_deq = head->fh2$w_recattr.fat$w_defext; + fab->fab$b_fsz = head->fh2$w_recattr.fat$b_vfcsize; + fab->fab$w_gbc = head->fh2$w_recattr.fat$w_gbc; + fab->fab$w_mrs = head->fh2$w_recattr.fat$w_maxrec; + fab->fab$b_org = head->fh2$w_recattr.fat$b_rtype & 0xf0; + fab->fab$b_rfm = head->fh2$w_recattr.fat$b_rtype & 0x0f; + fab->fab$b_rat = head->fh2$w_recattr.fat$b_rattrib; + while (xab != NULL) { + switch (xab->xab$b_cod) { + case XAB$C_DAT: + memcpy(&xab->xab$q_bdt,&id->fi2$q_bakdate,sizeof(struct TIME)); + memcpy(&xab->xab$q_cdt,&id->fi2$q_credate,sizeof(struct TIME)); + memcpy(&xab->xab$q_edt,&id->fi2$q_expdate,sizeof(struct TIME)); + memcpy(&xab->xab$q_rdt,&id->fi2$q_revdate,sizeof(struct TIME)); + xab->xab$w_rvn = id->fi2$w_revision; + break; + case XAB$C_FHC:{ + struct XABFHC *fhc = (struct XABFHC *) xab; + fhc->xab$b_atr = head->fh2$w_recattr.fat$b_rattrib; + fhc->xab$b_bkz = head->fh2$w_recattr.fat$b_bktsize; + fhc->xab$w_dxq = head->fh2$w_recattr.fat$w_defext; + fhc->xab$l_ebk = swapw(head->fh2$w_recattr.fat$l_efblk); + fhc->xab$w_ffb = head->fh2$w_recattr.fat$w_ffbyte; + if (fhc->xab$l_ebk == 0) { + fhc->xab$l_ebk = fab->fab$l_alq; + if (fhc->xab$w_ffb == 0) fhc->xab$l_ebk++; + } + fhc->xab$w_gbc = head->fh2$w_recattr.fat$w_gbc; + fhc->xab$l_hbk = swapw(head->fh2$w_recattr.fat$l_hiblk); + fhc->xab$b_hsz = head->fh2$w_recattr.fat$b_vfcsize; + fhc->xab$w_lrl = head->fh2$w_recattr.fat$w_maxrec; + fhc->xab$w_verlimit = head->fh2$w_recattr.fat$w_versions; + } + break; + case XAB$C_PRO:{ + struct XABPRO *pro = (struct XABPRO *) xab; + pro->xab$w_pro = head->fh2$w_fileprot; + memcpy(&pro->xab$l_uic,&head->fh2$l_fileowner,4); + } + } + xab = xab->xab$l_nxt; + } + + return 1; +} + + +/* close a file */ + +unsigned sys_close(struct FAB *fab) +{ + int sts; + int ifi_no = fab->fab$w_ifi; + if (ifi_no < 1 || ifi_no >= IFI_MAX) return RMS$_IFI; + sts = deaccessfile(ifi_table[ifi_no]->wcf_fcb); + if (sts & 1) { + ifi_table[ifi_no]->wcf_fcb = NULL; + if (ifi_table[ifi_no]->wcf_status & STATUS_TMPWCC) { + cleanup_wcf(ifi_table[ifi_no]); + if (fab->fab$l_nam != NULL) fab->fab$l_nam->nam$l_wcc = 0; + } + fab->fab$w_ifi = 0; + ifi_table[ifi_no] = NULL; + } + return sts; +} + + +/* open a file */ + +unsigned sys_open(struct FAB *fab) +{ + unsigned sts; + int ifi_no = 1; + int wcc_flag = 0; + struct WCCFILE *wccfile = NULL; + struct NAM *nam = fab->fab$l_nam; + if (fab->fab$w_ifi != 0) return RMS$_IFI; + while (ifi_table[ifi_no] != NULL && ifi_no < IFI_MAX) ifi_no++; + if (ifi_no >= IFI_MAX) return RMS$_IFI; + if (nam != NULL) { + wccfile = (struct WCCFILE *) nam->nam$l_wcc; + } + if (wccfile == NULL) { + sts = do_parse(fab,&wccfile); + if (sts & 1) { + wcc_flag = 1; + if (wccfile->wcf_status & STATUS_WILDCARD) { + sts = RMS$_WLD; + } else { + sts = do_search(fab,wccfile); + } + wccfile->wcf_status |= STATUS_TMPWCC; + } + } else { + sts = 1; + } + if (sts & 1) sts = accessfile(wccfile->wcf_vcb,&wccfile->wcf_fid,&wccfile->wcf_fcb,0); + if (sts & 1) { + ifi_table[ifi_no] = wccfile; + fab->fab$w_ifi = ifi_no; + sys_display(fab); + } + if (wcc_flag && ((sts & 1) == 0)) { + cleanup_wcf(wccfile); + if (nam != NULL) nam->nam$l_wcc = 0; + } + return sts; +} + + +/* blow away a file */ + +unsigned sys_erase(struct FAB *fab) +{ + unsigned sts; + int ifi_no = 1; + int wcc_flag = 0; + struct WCCFILE *wccfile = NULL; + struct NAM *nam = fab->fab$l_nam; + if (fab->fab$w_ifi != 0) return RMS$_IFI; + while (ifi_table[ifi_no] != NULL && ifi_no < IFI_MAX) ifi_no++; + if (ifi_no >= IFI_MAX) return RMS$_IFI; + if (nam != NULL) { + wccfile = (struct WCCFILE *) fab->fab$l_nam->nam$l_wcc; + } + if (wccfile == NULL) { + sts = do_parse(fab,&wccfile); + if (sts & 1) { + wcc_flag = 1; + if (wccfile->wcf_status & STATUS_WILDCARD) { + sts = RMS$_WLD; + } else { + sts = do_search(fab,wccfile); + } + } + } else { + sts = 1; + } + if (sts & 1) { + struct fibdef fibblk; + struct dsc$descriptor fibdsc,serdsc; + fibdsc.dsc$w_length = sizeof(struct fibdef); + fibdsc.dsc$a_pointer = (char *) &fibblk; + serdsc.dsc$w_length = wccfile->wcf_wcd.wcd_reslen; + serdsc.dsc$a_pointer = wccfile->wcf_result + wccfile->wcf_wcd.wcd_prelen; + memcpy(&fibblk.fib$w_did_num,&wccfile->wcf_wcd.wcd_dirid,sizeof(struct fiddef)); + fibblk.fib$w_nmctl = 0; + fibblk.fib$l_acctl = 0; + fibblk.fib$w_fid_num = 0; + fibblk.fib$w_fid_seq = 0; + fibblk.fib$b_fid_rvn = 0; + fibblk.fib$b_fid_nmx = 0; + fibblk.fib$l_wcc = 0; + sts = direct(wccfile->wcf_vcb,&fibdsc,&serdsc,NULL,NULL,1); + if (sts & 1) sts = accesserase(wccfile->wcf_vcb,&wccfile->wcf_fid); + } + if (wcc_flag) { + cleanup_wcf(wccfile); + if (nam != NULL) nam->nam$l_wcc = 0; + } + return sts; +} diff --git a/extracters/ods2/rms.h b/extracters/ods2/rms.h new file mode 100644 index 0000000..4f875ff --- /dev/null +++ b/extracters/ods2/rms.h @@ -0,0 +1,229 @@ +/* RMS.H v1.2 RMS routine definitions */ + +/* + This is part of ODS2 written by Paul Nankervis, + email address: Paulnank@au1.ibm.com + + ODS2 is distributed freely for all members of the + VMS community to use. However all derived works + must maintain comments in their source to acknowledge + the contibution of the original author. +*/ + +/* If not using GNU C on VMS use real RMS structures :-)... + otherwise define minimum subset to meet our requirements */ + +#if defined(VMS) && !defined(__GNUC__) + +#include + +#else + +#include "vmstime.h" + +#define RMS$_RTB 98728 +#define RMS$_EOF 98938 +#define RMS$_FNF 98962 +#define RMS$_NMF 99018 +#define RMS$_WCC 99050 +#define RMS$_BUG 99380 +#define RMS$_DIR 99532 +#define RMS$_ESS 99588 +#define RMS$_FNM 99628 +#define RMS$_IFI 99684 +#define RMS$_NAM 99804 +#define RMS$_RSS 99988 +#define RMS$_WLD 100164 +#define RMS$_DNF 114762 + +#define NAM$C_MAXRSS 255 +#define NAM$M_SYNCHK 1 +#define FAB$M_NAM 0x1000000 + +#define XAB$C_DAT 18 +#define XAB$C_FHC 29 +#define XAB$C_PRO 19 + +struct XABDAT { + void *xab$l_nxt; + int xab$b_cod; + int xab$w_rvn; + struct TIME xab$q_bdt; + struct TIME xab$q_cdt; + struct TIME xab$q_edt; + struct TIME xab$q_rdt; +}; + +#ifdef RMS_INITIALIZE +struct XABDAT cc$rms_xabdat = {NULL,XAB$C_DAT,0, + {{0,0,0,0,0,0,0,0}}, {{0,0,0,0,0,0,0,0}}, + {{0,0,0,0,0,0,0,0}}, {{0,0,0,0,0,0,0,0}}}; +#else +extern struct XABDAT cc$rms_xabdat; +#endif + + + +struct XABFHC { + void *xab$l_nxt; + int xab$b_cod; + int xab$b_atr; + int xab$b_bkz; + int xab$w_dxq; + int xab$l_ebk; + int xab$w_ffb; + int xab$w_gbc; + int xab$l_hbk; + int xab$b_hsz; + int xab$w_lrl; + int xab$w_verlimit; +}; + +#ifdef RMS_INITIALIZE +struct XABFHC cc$rms_xabfhc = {NULL,XAB$C_FHC,0,0,0,0,0,0,0,0,0,0}; +#else +extern struct XABFHC cc$rms_xabfhc; +#endif + + + +struct XABPRO { + void *xab$l_nxt; + int xab$b_cod; + int xab$w_pro; + int xab$l_uic; +}; + +#ifdef RMS_INITIALIZE +struct XABPRO cc$rms_xabpro = {NULL,XAB$C_PRO,0,0}; +#else +extern struct XABPRO cc$rms_xabpro; +#endif + +#define NAM$M_WILDCARD 0x100 + +struct NAM { + unsigned short nam$w_did_num; + unsigned short nam$w_did_seq; + unsigned char nam$b_did_rvn; + unsigned char nam$b_did_nmx; + unsigned short nam$w_fid_num; + unsigned short nam$w_fid_seq; + unsigned char nam$b_fid_rvn; + unsigned char nam$b_fid_nmx; + int nam$b_ess; + int nam$b_rss; + int nam$b_esl; + char *nam$l_esa; + int nam$b_rsl; + char *nam$l_rsa; + int nam$b_dev; + char *nam$l_dev; + int nam$b_dir; + char *nam$l_dir; + int nam$b_name; + char *nam$l_name; + int nam$b_type; + char *nam$l_type; + int nam$b_ver; + char *nam$l_ver; + int nam$l_wcc; + int nam$b_nop; + int nam$l_fnb; +}; + +#ifdef RMS_INITIALIZE +struct NAM cc$rms_nam = {0,0,0,0,0,0,0,0,0,0,0,NULL,0,NULL,0,NULL,0,NULL,0,NULL,0,NULL,0,NULL,0,0,0}; +#else +extern struct NAM cc$rms_nam; +#endif + +#define RAB$C_SEQ 0 +#define RAB$C_RFA 2 + +struct RAB { + struct FAB *rab$l_fab; + char *rab$l_ubf; + char *rab$l_rhb; + unsigned rab$w_usz; + unsigned rab$w_rsz; + int rab$b_rac; + unsigned short rab$w_rfa[3]; +}; + +#ifdef RMS_INITIALIZE +struct RAB cc$rms_rab = {NULL,NULL,NULL,0,0,0,{0,0,0}}; +#else +extern struct RAB cc$rms_rab; +#endif + + +#define FAB$C_SEQ 0 +#define FAB$C_REL 16 +#define FAB$C_IDX 32 +#define FAB$C_HSH 48 + +#define FAB$M_FTN 1 +#define FAB$M_CR 2 +#define FAB$M_PRN 4 +#define FAB$M_BLK 8 + +#define FAB$C_UDF 0 +#define FAB$C_FIX 1 +#define FAB$C_VAR 2 +#define FAB$C_VFC 3 +#define FAB$C_STM 4 +#define FAB$C_STMLF 5 +#define FAB$C_STMCR 6 + +struct FAB { + struct NAM *fab$l_nam; + int fab$w_ifi; + char *fab$l_fna; + char *fab$l_dna; + int fab$b_fns; + int fab$b_dns; + int fab$l_alq; + int fab$b_bks; + int fab$w_deq; + int fab$b_fsz; + int fab$w_gbc; + int fab$w_mrs; + int fab$l_fop; + int fab$b_org; + int fab$b_rat; + int fab$b_rfm; + void *fab$l_xab; +}; + +#ifdef RMS_INITIALIZE +struct FAB cc$rms_fab = {NULL,0,NULL,NULL,0,0,0,0,0,0,0,0,0,0,0,0,NULL}; +#else +extern struct FAB cc$rms_fab; +#endif +#endif + + +#define sys$search sys_search +#define sys$parse sys_parse +#define sys$setddir sys_setddir +#define sys$connect sys_connect +#define sys$disconnect sys_disconnect +#define sys$get sys_get +#define sys$display sys_display +#define sys$close sys_close +#define sys$open sys_open +#define sys$erase sys_erase + + +unsigned sys_search(struct FAB *fab); +unsigned sys_parse(struct FAB *fab); +unsigned sys_connect(struct RAB *rab); +unsigned sys_disconnect(struct RAB *rab); +unsigned sys_get(struct RAB *rab); +unsigned sys_display(struct FAB *fab); +unsigned sys_close(struct FAB *fab); +unsigned sys_open(struct FAB *fab); +unsigned sys_erase(struct FAB *fab); +unsigned sys_setddir(struct dsc$descriptor *newdir,unsigned short *oldlen, + struct dsc$descriptor *olddir); diff --git a/extracters/ods2/ssdef.h b/extracters/ods2/ssdef.h new file mode 100644 index 0000000..e1bedf2 --- /dev/null +++ b/extracters/ods2/ssdef.h @@ -0,0 +1,48 @@ +/* Ssdef.h v1.2 System status definitions */ + +/* + This is part of ODS2 written by Paul Nankervis, + email address: Paulnank@au1.ibm.com + + ODS2 is distributed freely for all members of the + VMS community to use. However all derived works + must maintain comments in their source to acknowledge + the contibution of the original author. +*/ + + +#ifdef VMS + +#include + +#else + +#define SS$_NORMAL 1 +#define SS$_WASCLR 1 +#define SS$_WASSET 9 +#define SS$_ABORT 44 +#define SS$_DEVNOTMOUNT 124 +#define SS$_ILLEFC 236 +#define SS$_INSFMEM 292 +#define SS$_DATACHECK 92 +#define SS$_BUGCHECK 676 +#define SS$_DUPLICATE 148 +#define SS$_BADPARAM 20 +#define SS$_IVCHAN 316 +#define SS$_NOIOCHAN 436 +#define SS$_PARITY 500 +#define SS$_WRITLCK 604 +#define SS$_DEVNOTALLOC 2136 +#define SS$_DUPFILENAME 2152 +#define SS$_NOSUCHDEV 2312 +#define SS$_NOSUCHFILE 2320 +#define SS$_BADFILENAME 2072 +#define SS$_BADIRECTORY 2088 +#define SS$_ENDOFFILE 2160 +#define SS$_FILELOCKED 2216 +#define SS$_NOMOREFILES 2352 +#define SS$_NOSUCHVOL 3882 +#define SS$_NOTINSTALL 8212 +#define SS$_DEVNOTDISM 8628 + +#endif diff --git a/extracters/ods2/vmstime.c b/extracters/ods2/vmstime.c new file mode 100644 index 0000000..2caf8b5 --- /dev/null +++ b/extracters/ods2/vmstime.c @@ -0,0 +1,754 @@ +/* + + VMSTIME.C v1.2 + + Author: Paul Nankervis + + V1.2 - cleanup to stop compiler warnings + + Please send bug reports or requests for enhancement + or improvement via email to: PaulNank@au1.ibm.com + + + This module contains versions of the VMS time routines + sys$numtim(), sys$asctim() and friends... They are + intended to be compatible with the routines of the same + name on a VMS system (so descriptors feature regularly!) + + This code relies on being able to manipluate day numbers + and times using 32 bit arithmetic to crack a VMS quadword + byte by byte. If your C compiler doesn't have 32 bit int + fields give up now! On a 64 bit systems this code could + be modified to do 64 bit operations directly.... + + One advantage of doing arihmetic byte by byte is that + the code does not depend on what 'endian' the target + machine is - it will always treat bytes in the same order! + (Hopefully VMS time bytes will always be in the same order!) + + A couple of stupid questions to go on with:- + o OK, I give up! What is the difference between a zero + date and a zero delta time? + o Anyone notice that the use of 16 bit words in + sys$numtim restricts delta times to 65535 days? + + Paul Nankervis + +*/ + + +#include +#include +#include "vmstime.h" /* Our header file! */ +#include /* C header for $GETTIM to find time */ + + + +#ifndef SS$_NORMAL +#define SS$_NORMAL 1 +#define SS$_IVTIME 388 +#define LIB$_ONEDELTIM 1410020 +#endif + + +#define TIMEBASE 100000 /* 10 millisecond units in quadword */ +#define TIMESIZE 8640000 /* Factor between dates & times */ + +#define QUAD_CENTURY_DAYS 146097 +/* (400*365) + (400/4) - (400/100) + (400/400) */ +#define CENTURY_DAYS 36524 +/* (100*365) + (100/4) - (100/100) */ +#define QUAD_YEAR_DAYS 1461 +/* (4*365) + (4/4) */ +#define YEAR_DAYS 365 +/* 365 */ +#define OFFSET_DAYS 94187 +/* ((1858_1601)*365) + ((1858_1601)/4) - ((1858_1601)/100) + + ((1858_1601)/400) + 320 + OFFSET FROM 1/1/1601 TO 17/11/1858 */ +#define BASE_YEAR 1601 + + + +/* combine_date_time() is an internal routine to put date and time into a + quadword - basically the opposite of lib_day() .... */ + +unsigned combine_date_time(int days,struct TIME *timadr,int day_time) +{ + if (day_time >= TIMESIZE) { + return SS$_IVTIME; + } else { + + /* Put days into quad timbuf... */ + + register unsigned count,time; + register unsigned char *ptr; + count = 8; + ptr = timadr->time; + time = days; + do { + *ptr++ = time; + time = (time >> 8); + } while (--count > 0); + + /* Factor in the time... */ + + count = 8; + ptr = timadr->time; + time = day_time; + do { + time += *ptr * TIMESIZE; + *ptr++ = time; + time = (time >> 8); + } while (--count > 0); + + /* Factor by time base... */ + + count = 8; + ptr = timadr->time; + time = 0; + do { + time += *ptr * TIMEBASE; + *ptr++ = time; + time = (time >> 8); + } while (--count > 0); + + return SS$_NORMAL; + } +} + + + +/* sys_gettim() implemented here by getting UNIX time in seconds since + 1-Jan-1970 using time() and munging into a quadword... Some run time + systems don't seem to do this properly!!! Note that time() has a + resolution of only one second. */ + +unsigned sys_gettim(struct TIME *timadr) +{ + time_t curtim = time(NULL); + return combine_date_time(40587 + curtim / 86400,timadr, + (curtim % 86400) * 100); +} + + +/* lib_cvt_vectim() takes individual time fields in seven word buffer and + munges into a quadword... */ + +unsigned short month_end[] = {0,31,59,90,120,151,181,212,243,273,304,334,365}; + +unsigned lib_cvt_vectim(unsigned short timbuf[7],struct TIME *timadr) +{ + int delta = 0; + register unsigned sts,days,day_time; + sts = SS$_NORMAL; + + /* lib_cvt_vectim packs the seven date/time components into a quadword... */ + + if (timbuf[0] == 0 && timbuf[1] == 0) { + delta = 1; + days = timbuf[2]; + } else { + register int leap = 0,year = timbuf[0],month = timbuf[1]; + if (month >= 2) { + if ((year % 4) == 0) { + if ((year % 100) == 0) { + if ((year % 400) == 0) { + leap = 1; + } + } else { + leap = 1; + } + } + } + days = timbuf[2]; + if (year >= 1858 && year <= 9999 && month >= 1 && + month <= 12 && days >= 1) { + days += month_end[month - 1]; + if (month > 2) days += leap; + if (days <= month_end[month] + leap) { + year -= BASE_YEAR; + days += year * 365 + year / 4 - year / 100 + year / 400 + - OFFSET_DAYS - 1; + } else { + sts = SS$_IVTIME; + } + } else { + sts = SS$_IVTIME; + } + } + if (timbuf[3] > 23 || timbuf[4] > 59 || + timbuf[5] > 59 || timbuf[6] > 99) { + sts = SS$_IVTIME; + } + if (sts & 1) { + day_time = timbuf[3] * 360000 + timbuf[4] * 6000 + + timbuf[5] * 100 + timbuf[6]; + sts = combine_date_time(days,timadr,day_time); + if (delta) { + + /* We have to 2's complement delta times - sigh!! */ + + register unsigned count,time; + register unsigned char *ptr; + count = 8; + ptr = timadr->time; + time = 1; + do { + time = time + ((~*ptr) & 0xFF); + *ptr++ = time; + time = (time >> 8); + } while (--count > 0); + } + } + return sts; +} + + +/* lib_day() is a routine to crack quadword into day number and time */ + +unsigned lib_day(int *days,struct TIME *timadr,int *day_time) +{ + register unsigned date,time,count; + register unsigned char *dstptr,*srcptr; + struct TIME wrktim; + int delta; + + /* If no time specified get current using gettim() */ + + if (timadr == NULL) { + register unsigned sts; + sts = sys_gettim(&wrktim); + if ((sts & 1) == 0) { + return sts; + } + delta = 0; + srcptr = wrktim.time + 7; + } else { + + /* Check specified time for delta... */ + + srcptr = timadr->time + 7; + if ((delta = (*srcptr & 0x80))) { + + /* We have to 2's complement delta times - sigh!! */ + + count = 8; + srcptr = timadr->time; + dstptr = wrktim.time; + time = 1; + do { + time = time + ((~*srcptr++) & 0xFF); + *dstptr++ = time; + time = (time >> 8); + } while (--count > 0); + srcptr = wrktim.time + 7; + } + } + + + /* Throw away the unrequired time precision */ + + count = 8; + dstptr = wrktim.time + 7; + time = 0; + do { + time = (time << 8) | *srcptr--; + *dstptr-- = time / TIMEBASE; + time %= TIMEBASE; + } while (--count > 0); + + + /* Seperate the date and time */ + + date = time = 0; + srcptr = wrktim.time + 7; + count = 8; + do { + time = (time << 8) | *srcptr--; + date = (date << 8) | (time / TIMESIZE); + time %= TIMESIZE; + } while (--count > 0); + + /* Return results... */ + + if (delta) { + *days = -(int) date; + if (day_time != NULL) *day_time = -(int) time; + } else { + *days = date; + if (day_time != NULL) *day_time = time; + } + + return SS$_NORMAL; +} + + + +/* sys_numtim() takes quadword and breaks it into a seven word time buffer */ + +unsigned char month_days[] = {31,29,31,30,31,30,31,31,30,31,30,31}; + +unsigned sys_numtim(unsigned short timbuf[7],struct TIME *timadr) +{ + register int date,time; + + /* Use lib_day to crack time into date/time... */ + + { + int days,day_time; + register unsigned sts; + sts = lib_day(&days,timadr,&day_time); + if ((sts & 1) == 0) { + return sts; + } + date = days; + time = day_time; + } + + /* Delta or date... */ + + if (date < 0 || time < 0) { + timbuf[2] = -date; /* Days */ + timbuf[1] = 0; /* Month */ + timbuf[0] = 0; /* Year */ + time = -time; + + } else { + + /* Date... */ + + register int year,month; + date += OFFSET_DAYS; + year = BASE_YEAR + (date / QUAD_CENTURY_DAYS) * 400; + date %= QUAD_CENTURY_DAYS; + + /* Kludge century division - last century in quad is longer!! */ + + if ((month = date / CENTURY_DAYS) == 4) month = 3; + date -= month * CENTURY_DAYS; + year += month * 100; + + /* Use the same technique to find out the quad year and year - + last year in quad is longer!! */ + + year += (date / QUAD_YEAR_DAYS) * 4; + date %= QUAD_YEAR_DAYS; + + if ((month = date / YEAR_DAYS) == 4) month = 3; + date -= month * YEAR_DAYS; + year += month; + + /* Adjust for years which have no Feb 29th */ + + if (date++ > 58) { + if (month != 3) { + date++; + } else { + if ((year % 100) == 0 && (year % 400) != 0) date++; + } + } + /* Figure out what month it is... */ + + { + unsigned char *mthptr = month_days; + month = 1; + while (date > *mthptr) { + date -= *mthptr++; + month++; + } + } + + /* Return date results... */ + + timbuf[2] = date; /* Days */ + timbuf[1] = month; /* Month */ + timbuf[0] = year; /* Year */ + } + + /* Return time... */ + + timbuf[6] = time % 100; /* Hundredths */ + time /= 100; + timbuf[5] = time % 60; /* Seconds */ + time /= 60; + timbuf[4] = time % 60; /* Minutes */ + timbuf[3] = time / 60; /* Hours */ + + return SS$_NORMAL; +} + + + +/* sys_bintim() takes ascii time and convert it to a quadword */ + +char month_names[] = "-JAN-FEB-MAR-APR-MAY-JUN-JUL-AUG-SEP-OCT-NOV-DEC-"; +char time_sep[] = "::."; + +unsigned sys_bintim(struct dsc$descriptor *timbuf,struct TIME *timadr) +{ + register int length = timbuf->dsc$w_length; + register char *chrptr = timbuf->dsc$a_pointer; + unsigned short wrktim[7]; + int num,tf; + + + /* Skip leading spaces... */ + + while (length > 0 && *chrptr == ' ') { + length--; + chrptr++; + } + + /* Get the day number... */ + + num = -1; + if (length > 0 && *chrptr >= '0' && *chrptr <= '9') { + num = 0; + do { + num = num * 10 + (*chrptr++ - '0'); + } while (--length > 0 && *chrptr >= '0' && *chrptr <= '9'); + } + /* Check for month separator "-" - if none delta time... */ + + if (length > 0 && *chrptr == '-') { + chrptr++; + + /* Get current time for defaults... */ + + sys_numtim(wrktim,NULL); + if (num >= 0) wrktim[2] = num; + num = 0; + if (--length >= 3 && *chrptr != '-') { + char *mn = month_names + 1; + num = 1; + while (num <= 12) { + if (memcmp(chrptr,mn,3) == 0) break; + mn += 4; + num++; + } + chrptr += 3; + length -= 3; + wrktim[1] = num; + } + /* Now look for year... */ + + if (length > 0 && *chrptr == '-') { + length--; + chrptr++; + if (length > 0 && *chrptr >= '0' && *chrptr <= '9') { + num = 0; + do { + num = num * 10 + (*chrptr++ - '0'); + } while (--length > 0 && *chrptr >= '0' && *chrptr <= '9'); + wrktim[0] = num; + } + } + } else { + + /* Delta time then... */ + + wrktim[0] = wrktim[1] = 0; + wrktim[2] = num; + wrktim[3] = wrktim[4] = wrktim[5] = wrktim[6] = 0; + } + + /* Skip any spaces between date and time... */ + + while (length > 0 && *chrptr == ' ') { + length--; + chrptr++; + } + + /* Now wrap up time fields... */ + + for (tf = 0; tf < 3; tf++) { + if (length > 0 && *chrptr >= '0' && *chrptr <= '9') { + num = 0; + do { + num = num * 10 + (*chrptr++ - '0'); + } while (--length > 0 && *chrptr >= '0' && *chrptr <= '9'); + wrktim[3 + tf] = num; + if (num > 59) wrktim[1] = 13; + } + if (length > 0 && *chrptr == time_sep[tf]) { + length--; + chrptr++; + } else { + break; + } + } + + /* Hundredths of seconds need special handling... */ + + if (length > 0 && *chrptr >= '0' && *chrptr <= '9') { + tf = 10; + num = 0; + do { + num = num + tf * (*chrptr++ - '0'); + tf = tf / 10; + } while (--length > 0 && *chrptr >= '0' && *chrptr <= '9'); + wrktim[6] = num; + } + /* Now skip any trailing spaces... */ + + while (length > 0 && *chrptr == ' ') { + length--; + chrptr++; + } + + /* If anything left then we have a problem... */ + + if (length == 0) { + return lib_cvt_vectim(wrktim,timadr); + } else { + return SS$_IVTIME; + } +} + + +/* sys_asctim() converts quadword to ascii... */ + +unsigned sys_asctim(unsigned short *timlen,struct dsc$descriptor *timbuf, + struct TIME *timadr,unsigned cvtflg) +{ + register int count,timval; + unsigned short wrktim[7]; + register int length = timbuf->dsc$w_length; + register char *chrptr = timbuf->dsc$a_pointer; + + /* First use sys_numtim to get the date/time fields... */ + + { + register unsigned sts; + sts = sys_numtim(wrktim,timadr); + if ((sts & 1) == 0) { + return sts; + } + } + + /* See if we want delta days or date... */ + + if (cvtflg == 0) { + + /* Check if date or delta time... */ + + if (*wrktim) { + + /* Put in days and month... */ + + if (length > 0) { + if ((timval = wrktim[2]) / 10 == 0) { + *chrptr++ = ' '; + } else { + *chrptr++ = '0' + timval / 10; + } + length--; + } + if (length > 0) { + *chrptr++ = '0' + (timval % 10); + length--; + } + if ((count = length) > 5) count = 5; + memcpy(chrptr,month_names + (wrktim[1] * 4 - 4),count); + length -= count; + chrptr += count; + timval = *wrktim; + } else { + + /* Get delta days... */ + + timval = wrktim[2]; + } + + /* Common code for year number and delta days!! */ + + count = 10000; + if (timval < count) { + count = 1000; + while (length > 0 && timval < count && count > 1) { + length--; + *chrptr++ = ' '; + count /= 10; + } + } + while (length > 0 && count > 0) { + length--; + *chrptr++ = '0' + (timval / count); + timval = timval % count; + count /= 10; + } + + /* Space between date and time... */ + + if (length > 0) { + *chrptr++ = ' '; + length--; + } + } + /* Do time... :-) */ + + count = 3; + do { + timval = wrktim[count]; + if (length >= 1) *chrptr++ = '0' + (timval / 10); + if (length >= 2) { + *chrptr++ = '0' + (timval % 10); + length -= 2; + } else { + length = 0; + } + if (count < 6 && length > 0) { + length--; + if (count == 5) { + *chrptr++ = '.'; + } else { + *chrptr++ = ':'; + } + } + } while (++count < 7); + + /* We've done it - time to return length... */ + + if (timlen != NULL) *timlen = timbuf->dsc$w_length - length; + return SS$_NORMAL; +} + + +/* lib_day_of_week() computes day of week from quadword... */ + +unsigned lib_day_of_week(struct TIME *timadr,unsigned *weekday) +{ + int days; + register unsigned sts; + + /* Use lib_day to crack quadword... */ + + sts = lib_day(&days,timadr,NULL); + if (sts & 1) { + *weekday = ((days + 2) % 7) + 1; + } + return sts; +} + + +/* addx & subx COULD use 32 bit arithmetic to do a word at a time. But + this only works on hardware which has the same endian as the VAX! + (Intel works fine!! :-) ) So this version works byte by byte which + should work on VMS dates regardless of system endian - but they + will NOT perform arithmetic correctly for other data types on + systems with opposite endian!!! */ + +unsigned lib_addx(void *addant,void *addee,void *result,int *lenadd) +{ + register int count; + register unsigned carry = 0; + register unsigned char *ant = (unsigned char *) addant; + register unsigned char *ee = (unsigned char *) addee; + register unsigned char *res = (unsigned char *) result; + if (lenadd == NULL) { + count = 8; + } else { + count = *lenadd * 4; + } + + while (count-- > 0) { + carry = *ant++ + (carry + *ee++); + *res++ = carry; + carry = carry >> 8; + } + return SS$_NORMAL; +} + + +unsigned lib_subx(void *subant,void *subee,void *result,int *lenadd) +{ + register int count; + register unsigned carry = 0; + register unsigned char *ant = (unsigned char *) subant; + register unsigned char *ee = (unsigned char *) subee; + register unsigned char *res = (unsigned char *) result; + if (lenadd == NULL) { + count = 8; + } else { + count = *lenadd * 4; + } + + while (count-- > 0) { + carry = *ant++ - (carry + *ee++); + *res++ = carry; + carry = (carry >> 8) & 1; + + } + return SS$_NORMAL; +} + + + +unsigned lib_add_times(struct TIME *time1,struct TIME *time2, + struct TIME *result) +{ + if (time1->time[7] & 0x80) { + if (time2->time[7] & 0x80) { + return lib_addx(time1,time2,result,NULL); + } else { + return lib_subx(time2,time1,result,NULL); + } + } else { + if (time2->time[7] & 0x80) { + return lib_subx(time1,time2,result,NULL); + } else { + return LIB$_ONEDELTIM; + } + } +} + + + +unsigned lib_sub_times(struct TIME *time1,struct TIME *time2, + struct TIME *result) +{ + if ((time1->time[7] & 0x80) != (time2->time[7] & 0x80)) { + return lib_addx(time1,time2,result,NULL); + } else { + register int cmp,count = 7; + do { + if ((cmp = (time1->time[count] - time2->time[count]))) break; + } while (--count >= 0); + if (cmp < 0) { + return lib_subx(time1,time2,result,NULL); + } else { + return lib_subx(time2,time1,result,NULL); + } + } +} + + + +unsigned lib_mult_delta_time(int *multiple,struct TIME *timadr) +{ + register unsigned count = 8,carry = 0; + register int factor = *multiple; + register unsigned char *ptr = timadr->time; + + /* Check for delta time... */ + + if (timadr->time[7] & 0x80) { + + /* Use absolute factor... */ + + if (factor < 0) factor = -factor; + + /* Multiply delta time... */ + + do { + carry += *ptr * factor; + *ptr++ = carry; + carry = (carry >> 8); + } while (--count > 0); + + return SS$_NORMAL; + } else { + return SS$_IVTIME; + } +} diff --git a/extracters/ods2/vmstime.h b/extracters/ods2/vmstime.h new file mode 100644 index 0000000..a0ba082 --- /dev/null +++ b/extracters/ods2/vmstime.h @@ -0,0 +1,52 @@ +/* + + VMSTIME.H v1.1 + + Author: Paul Nankervis + + Please send bug reports to PaulNank@au1.ibm.com + +*/ + + +#ifndef __VMSTIME__ +#define __VMSTIME__ loaded + +#include "descrip.h" + + +struct TIME { + unsigned char time[8]; /* Structure of time */ +}; /* Look out Einstein!! :-) */ + +#define lib$add_times lib_add_times +#define lib$addx lib_addx +#define lib$cvt_vectim lib_cvt_vectim +#define lib$day lib_day +#define lib$day_of_week lib_day_of_week +#define lib$mult_delta_time lib_mult_delta_time +#define lib$sub_times lib_sub_times +#define lib$subx lib_subx +#define sys$asctim sys_asctim +#define sys$bintim sys_bintim +#define sys$gettim sys_gettim +#define sys$numtim sys_numtim + + +unsigned sys_gettim(struct TIME *timadr); +unsigned lib_cvt_vectim(unsigned short timbuf[7],struct TIME *timadr); +unsigned lib_day(int *days,struct TIME *timadr,int *day_time); +unsigned sys_numtim(unsigned short timbuf[7],struct TIME *timadr); +unsigned sys_bintim(struct dsc$descriptor *timbuf,struct TIME *timadr); +unsigned sys_asctim(unsigned short *timlen,struct dsc$descriptor *timbuf, + struct TIME *timadr,unsigned cvtflg); +unsigned lib_day_of_week(struct TIME *timadr,unsigned *weekday); +unsigned lib_addx(void *addant,void *addee,void *result,int *lenadd); +unsigned lib_subx(void *subant,void *subee,void *result,int *lenadd); +unsigned lib_add_times(struct TIME *time1,struct TIME *time2, + struct TIME *result); +unsigned lib_sub_times(struct TIME *time1,struct TIME *time2, + struct TIME *result); +unsigned lib_mult_delta_time(int *multiple,struct TIME *timadr); + +#endif diff --git a/extracters/tpdump.c b/extracters/tpdump.c new file mode 100644 index 0000000..7b6fb94 --- /dev/null +++ b/extracters/tpdump.c @@ -0,0 +1,184 @@ +/* Dump tapes in the format of the simh 1401 simulator. + See "usage" function below. +*/ + +#include + +/* From i1401_dat.h: */ + +char bcd_to_ascii_old[64] = { + ' ', '1', '2', '3', '4', '5', '6', '7', + '8', '9', '0', '#', '@', ':', '>', '(', + '^', '/', 'S', 'T', 'U', 'V', 'W', 'X', + 'Y', 'Z', '\'', ',', '%', '=', '\\', '+', + '-', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', '!', '$', '*', ']', ';', '_', + '&', 'A', 'B', 'C', 'D', 'E', 'F', 'G', + 'H', 'I', '?', '.', ')', '[', '<', '"' + }; + +char bcd_to_ascii_a[64] = { + ' ', '1', '2', '3', '4', '5', '6', '7', + '8', '9', '0', '#', '@', ':', '>', '{', + '^', '/', 'S', 'T', 'U', 'V', 'W', 'X', + 'Y', 'Z', '|', ',', '%', '~', '\\', '"', + '-', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', '!', '$', '*', ']', ';', '_', + '&', 'A', 'B', 'C', 'D', 'E', 'F', 'G', + 'H', 'I', '?', '.', ')', '[', '<', '}' + }; + +char bcd_to_ascii_h[64] = { + ' ', '1', '2', '3', '4', '5', '6', '7', + '8', '9', '0', '=', '\'', ':', '>', '{', + '^', '/', 'S', 'T', 'U', 'V', 'W', 'X', + 'Y', 'Z', '|', ',', '(', '~', '\\', '"', + '-', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', '!', '$', '*', ']', ';', '_', + '+', 'A', 'B', 'C', 'D', 'E', 'F', 'G', + 'H', 'I', '?', '.', ')', '[', '<', '}' + }; + +/* Interesting BCD characters, from i1401_defs.h */ + +#define BCD_BLANK 000 +#define BCD_ALT 020 +#define BCD_WM 035 + +size_t read_len ( FILE* fi ) +/* Read a little-endian four-byte number */ +{ unsigned char c; /* A Character from the file */ + size_t i; + size_t lc; /* The character, as a long int */ + size_t n; /* the number */ + if ( fread ( &c, 1, 1, fi ) == 0 ) + return (0); + n = c; i = 256; + if ( fread ( &c, 1, 1, fi ) == 0 ) + return (0); + n += i*c; + i *= 256; + if ( fread ( &c, 1, 1, fi ) == 0 ) + return (0); + n += i*c; + i *= 256; + if ( fread ( &c, 1, 1, fi ) == 0 ) + return (0); + n += i*c; + i *= 256; + return (n); +} + +void usage ( char* argv[] ) +{ printf ( "Usage: %s [options] \n", argv[0] ); + printf ( " Options: -w to print word marks on a separate line)\n" ); + printf ( " -# number of 'files' to print (default 1)\n"); + printf ( " -a print all of each record, including blank lines,\n"); + printf ( " which are otherwise suppressed (except for the last one)\n"); + printf ( " -e E11 format, i.e., don't require even-length records\n" ); + printf ( " -h Use the H (Fortran) print arrangement\n"); + printf ( " -o Use the 'old simh' print arrangement\n"); +} + +main ( int argc, char* argv[] ) +{ FILE* fi; + int all; /* "print all of a record, even blank lines" */ + char* bcd_to_ascii; /* Translation table, ..._a or ..._h */ + int cl; /* Command line argument index */ + int dowm; /* "do word marks" */ + int even; /* Require even-length records */ + int i, j; /* Subscript, loop inductor */ + int nb; /* Number of characters in print buffer so far */ + int nf, nft; /* Number of "files" */ + int np; /* Number of characters processed so far */ + int nr; /* Number of records dumped so far */ + char pr[101]; /* Buffer to print tape contents */ + size_t recsiz, recsiz2; /* Record size before, after */ + char wm[101]; /* Buffer to print word marks */ + + if ( argc < 2 ) + { usage( argv ); + return(1); + } + + all = 0; + bcd_to_ascii = bcd_to_ascii_a; + dowm = 0; + even = 1; + nf = 1; + for ( cl=1; cl<=argc; cl++ ) + { if ( argv[cl][0] != '-' ) break; + if ( argv[cl][1] == 'w' ) dowm = 1; + else if ( argv[cl][1] == 'a' ) all = 1; + else if ( argv[cl][1] == 'e' ) even = 0; + else if ( argv[cl][1] == 'h' ) bcd_to_ascii = bcd_to_ascii_h; + else if ( argv[cl][1] == 'o' ) bcd_to_ascii = bcd_to_ascii_old; + else if ( sscanf(argv[cl], "%d", &nft ) ) nf = -nft; + else + { usage ( argv ); + return(1); + } + } + + fi = fopen ( argv[cl], "r" ); + if ( fi == NULL ) + { printf ( "Unable to open %s\n", argv[cl] ); + return(2); + } + bcd_to_ascii[BCD_BLANK] = bcd_to_ascii[BCD_ALT]; /* use '^' for blank */ + nft = 1; + if ( nf > 1 ) printf ( "File %d\n", nft ); + while ( nf > 0 ) + { nf--; + for ( np=0; np<100; pr[np++]='.' ); + pr[100] = '\0'; + for ( np=5; np<=100; np+=5 ) /* Print a row of dots and column numbers */ + for ( nb=1, i=np; i>0; i/=10, nb++ ) pr[np-nb] = '0' + ( i%10 ); + printf ( " %s\n", pr ); + nr = 0; + while ( recsiz = read_len ( fi ) ) + { nb = 1; + nr++; + i = recsiz; + while ( i ) + { for ( np=0; np<101; pr[np]='^',wm[np++]=' ') ; /* Clear buffers */ + for ( np=0; i>0 && np<100; np++ ) + { if ( fread ( &pr[np], 1, 1, fi ) <= 0 ) + { printf ( "Error reading %s\n", argv[cl] ); + return(3); + } + i--; + pr[np] = bcd_to_ascii[pr[np]]; + if ( dowm ) + if ( pr[np] == bcd_to_ascii[BCD_WM] ) wm[np--] = '1'; + } + for ( j=np--; j>=0 && pr[j] == bcd_to_ascii[BCD_ALT] && + wm[j] == ' '; j-- ) ; + if ( ( j >= 0 ) || ( nb == 1 ) || all || ( i == 0 ) ) + { printf ( "%5d: ", nb ); + pr[np+1] = '\0'; + printf ( "%s", pr ); + if ( nb == 1 ) + { for ( j=np ; j++<100 ; printf ( " " ) ) ; + printf ( " Record %d", nr ); + } + printf ( "\n" ); + if ( dowm ) + { for ( ; np >= 0 && wm[np] == ' '; np-- ); + wm[++np] = '\0'; + printf ( " %s\n", wm ); + } + } + nb += 100; + } + if ( (recsiz & 1) && even ) fread ( pr, 1, 1, fi ); + recsiz2 = read_len ( fi ); + if ( recsiz2 != recsiz ) + { printf("Unequal starting and ending record sizes: %d != %d\n", + recsiz, recsiz2); + return(4); + } + } + if ( nf > 0 ) printf ( "File %d\n", ++nft ); + } +} diff --git a/ods2_readme.txt b/ods2_readme.txt index 4e72db1..78161e1 100644 --- a/ods2_readme.txt +++ b/ods2_readme.txt @@ -1,175 +1,175 @@ - ODS2 June '98 - - A Program to Read ODS2 Disk Volumes - - -Say, what is this? - ODS2 is a program to read VMS disk volumes written in VMS - ODS2 format. - -Why bother? - Well sometimes it is convenient to see what is on a VMS CD, - or copy files from VMS disk on another platform. Maybe in - future it could be used as a basis for a PC Bookreader - program, or possibly other software? - -What other platforms? - ODS2 is written in 'Standard C' with the intent that it can - be compiled and run on non-VMS systems. However this requires - a C compiler which has 32 bit 'int' types, 16 bit 'short' - types, and 8 bit 'char'. The current version does no special - 'endian' handling so it can only be run on systems which are - little-endian like the VAX. Fortunately that inludes Intel... - -Could it be made to run on big-endian systems? - Yes it could! This would probably best be done by defining - C macros or functions to extract words or long words from the - disk structures as appropriate. On a little-endian system these - would be simply pass-through, while on a big-endian system they - would reverse the byte order. I have not attempted this because - I don't have a suitable test system!! - -What else is needed? - Some operating system support is also required to read an - absolute disk sector from the target disk. This is NOT as - easy as it sounds. I do not currently have sufficient - documentation to set this up for as many platforms as I - would like!! However I do have modules to read disks under - VMS (easy!) and floppies and CD under OS2, Windows 95 and - Windows NT. - -How do I build it? - On a VMS system ODS2 can be compiled by executing the - procedure BUILD.COM. On other platforms you need to compile - Ods2.c, Rms.c, Direct.c, Access.c, Device.c, Cache.c, Vmstime.c, - and the appropriate Phy*.c routine for your system. On OS/2 I - compile using the gcc command:- - gcc -fdollars-in-identifiers ods2.c,rms.c,direct.c, - access.c,device.c,cache.c,phyos2.c,vmstime.c - -What can it do? - Basically ODS2 provides cut down DIRECTORY, COPY and - SEARCH commands for VMS volumes on non-VMS systems. These - can be used to find out what is on a VMS volume, and copy - files onto the local file sytem. - -What file types? - Basically ODS2 can only deal with sequential files. I do not - have information on how indexed file types are constructed, - and relative files are of limited interest. - -What about volume sets? - ODS2 does contain support for multi-volume sets. However there - is no checking that the correct volumes have been specified and - error handling is very fragile. You should ensure that you - specify volume set mount commands very carefully! - -What about ODS5? - Sorry, but I have no idea! I have not seen any ODS5 information - or specifications. Most likely this program will fall in a heap - when presented with an ODS5 disk volume. - -What about bugs? - There are plenty!! This code has been tested for several hours - by a single developer/user on one workstation (absolutely no - testing or input from any other person up to this point!). - Contrast this to the VMS filesystem which has had hundreds of - developers, millions of users, and has run on about 500,000 - systems over the last 20 years!! I would hope to fix some of - the more severe limitations and provide better error handling - fairly soon, perhaps even put some comments into the code? - Maybe the next release might have fewer bugs? - -It is free? - Yeap! It is provided 'as is' to help people in the VMS - community. However there is NO SUPPORT! I will try to fix - any reported problems, but as I really only get to work on - it while the kids are at Scouts on Monday nights, fixes - happen slowly! But if you have comments or suggestions then - please feel free to mail me! - -Can I use the code? - Yeap! You can use and modify the code provided that you - acknowledge the author in the source of any modules which use - any part of this code. I would also appreciate, where possible, - being sent any enhancements for my own use. - -Can I call the routines from my program? - You should be able to. Many of the modules follow an 'RMS' - sort of standard, and programs which only ever read RMS files - from C might be converted to read VMS volumes on another platform - without too much effort. In addition to the RMSish interface, - it would not be difficult to package up an $ASSIGN/$QIOW interface - for common file operations... - -What is the status of ODS2? - This is the first release - actually more like a prototype - than an real release! But it may generate useful feedback and - possibly be useful to others the way it is? However if you are - tempted to use this version for real file transfers, DO YOUR OWN - TESTING first! This program may not have encountered volumes and - files like yours and could easily generate garbage results!!! - -Is more work happening? - Yes! I find the program very useful moving stuff from my - VAXstation to my PC. I would like to be able to write ODS2 volumes - so that I can move files in the other direction! And yes I hope - to generally improve the code - particularly in the area of error - handling! - -Can I make a suggestion? - You sure can! If you see something which needs improvement then - let me know. It may be more interesting than whatever I am doing now! - In fact if I don't hear from anyone then I might even loose interest! - -Can I see a command sample? - Sure:- - C:> ODS2 - ODS2 v1.2 - $> mount E:,F: - %MOUNT-I-MOUNTED, Volume FOX1 mounted on E: - %MOUNT-I-MOUNTED, Volume FOX2 mounted on F: - $> direct/file E:[*...] - Directory E:[PNANKERVIS] - 3MONTH.LOWUSE;1 (51,20,2) - ACCTEST.COM;1 (137,4,1) - ACCTEST.EXE;1 (53,4,2) - ..... - $> set default E:[sys0.sysmgr] - $> dir [-.sys*...].% - ..... - $> copy *.c *.* - %COPY-S-COPIED, E:[SYS0.SYSMGR]ACCESS.C;1 copied to ACCESS.C (3 records) - .... - $> show time - 24-MAR-1998 20:15:23.5 - $> dismount E: - $> exit - -What commands are supported? - A summary is:- - mount DRIVE:[,DRIVE:...] - directory [/file|/size|/date] [FILE-SPEC] - copy FILE-SPEC OUTPUT-FILE - dismount DRIVE: - search FILE-SPEC STRING - set default DIR-SPEC - show default - show time - exit - Note - DRIVE: is normally the native system drive name, - for example D: might be a CD on a PC - xxx: might be - /dev/xxx on a Unix system. - - when a list of drives is specified on the mount command - they are assumed to contain a single valid volume set - (this is not validated!!) - - file-spec is in the usual VMS syntax and may contain - wildcards (for example A:[-.*obj%%...]*abc*.obj;-2) - -Who would write this? - Me! Maybe it will become the basis of something more? If you - have suggestions or want to know more then please mail me at - paulnank@au1.ibm.com - - Thanks for listening! - Paul Nankervis + ODS2 June '98 + + A Program to Read ODS2 Disk Volumes + + +Say, what is this? + ODS2 is a program to read VMS disk volumes written in VMS + ODS2 format. + +Why bother? + Well sometimes it is convenient to see what is on a VMS CD, + or copy files from VMS disk on another platform. Maybe in + future it could be used as a basis for a PC Bookreader + program, or possibly other software? + +What other platforms? + ODS2 is written in 'Standard C' with the intent that it can + be compiled and run on non-VMS systems. However this requires + a C compiler which has 32 bit 'int' types, 16 bit 'short' + types, and 8 bit 'char'. The current version does no special + 'endian' handling so it can only be run on systems which are + little-endian like the VAX. Fortunately that inludes Intel... + +Could it be made to run on big-endian systems? + Yes it could! This would probably best be done by defining + C macros or functions to extract words or long words from the + disk structures as appropriate. On a little-endian system these + would be simply pass-through, while on a big-endian system they + would reverse the byte order. I have not attempted this because + I don't have a suitable test system!! + +What else is needed? + Some operating system support is also required to read an + absolute disk sector from the target disk. This is NOT as + easy as it sounds. I do not currently have sufficient + documentation to set this up for as many platforms as I + would like!! However I do have modules to read disks under + VMS (easy!) and floppies and CD under OS2, Windows 95 and + Windows NT. + +How do I build it? + On a VMS system ODS2 can be compiled by executing the + procedure BUILD.COM. On other platforms you need to compile + Ods2.c, Rms.c, Direct.c, Access.c, Device.c, Cache.c, Vmstime.c, + and the appropriate Phy*.c routine for your system. On OS/2 I + compile using the gcc command:- + gcc -fdollars-in-identifiers ods2.c,rms.c,direct.c, + access.c,device.c,cache.c,phyos2.c,vmstime.c + +What can it do? + Basically ODS2 provides cut down DIRECTORY, COPY and + SEARCH commands for VMS volumes on non-VMS systems. These + can be used to find out what is on a VMS volume, and copy + files onto the local file sytem. + +What file types? + Basically ODS2 can only deal with sequential files. I do not + have information on how indexed file types are constructed, + and relative files are of limited interest. + +What about volume sets? + ODS2 does contain support for multi-volume sets. However there + is no checking that the correct volumes have been specified and + error handling is very fragile. You should ensure that you + specify volume set mount commands very carefully! + +What about ODS5? + Sorry, but I have no idea! I have not seen any ODS5 information + or specifications. Most likely this program will fall in a heap + when presented with an ODS5 disk volume. + +What about bugs? + There are plenty!! This code has been tested for several hours + by a single developer/user on one workstation (absolutely no + testing or input from any other person up to this point!). + Contrast this to the VMS filesystem which has had hundreds of + developers, millions of users, and has run on about 500,000 + systems over the last 20 years!! I would hope to fix some of + the more severe limitations and provide better error handling + fairly soon, perhaps even put some comments into the code? + Maybe the next release might have fewer bugs? + +It is free? + Yeap! It is provided 'as is' to help people in the VMS + community. However there is NO SUPPORT! I will try to fix + any reported problems, but as I really only get to work on + it while the kids are at Scouts on Monday nights, fixes + happen slowly! But if you have comments or suggestions then + please feel free to mail me! + +Can I use the code? + Yeap! You can use and modify the code provided that you + acknowledge the author in the source of any modules which use + any part of this code. I would also appreciate, where possible, + being sent any enhancements for my own use. + +Can I call the routines from my program? + You should be able to. Many of the modules follow an 'RMS' + sort of standard, and programs which only ever read RMS files + from C might be converted to read VMS volumes on another platform + without too much effort. In addition to the RMSish interface, + it would not be difficult to package up an $ASSIGN/$QIOW interface + for common file operations... + +What is the status of ODS2? + This is the first release - actually more like a prototype + than an real release! But it may generate useful feedback and + possibly be useful to others the way it is? However if you are + tempted to use this version for real file transfers, DO YOUR OWN + TESTING first! This program may not have encountered volumes and + files like yours and could easily generate garbage results!!! + +Is more work happening? + Yes! I find the program very useful moving stuff from my + VAXstation to my PC. I would like to be able to write ODS2 volumes + so that I can move files in the other direction! And yes I hope + to generally improve the code - particularly in the area of error + handling! + +Can I make a suggestion? + You sure can! If you see something which needs improvement then + let me know. It may be more interesting than whatever I am doing now! + In fact if I don't hear from anyone then I might even loose interest! + +Can I see a command sample? + Sure:- + C:> ODS2 + ODS2 v1.2 + $> mount E:,F: + %MOUNT-I-MOUNTED, Volume FOX1 mounted on E: + %MOUNT-I-MOUNTED, Volume FOX2 mounted on F: + $> direct/file E:[*...] + Directory E:[PNANKERVIS] + 3MONTH.LOWUSE;1 (51,20,2) + ACCTEST.COM;1 (137,4,1) + ACCTEST.EXE;1 (53,4,2) + ..... + $> set default E:[sys0.sysmgr] + $> dir [-.sys*...].% + ..... + $> copy *.c *.* + %COPY-S-COPIED, E:[SYS0.SYSMGR]ACCESS.C;1 copied to ACCESS.C (3 records) + .... + $> show time + 24-MAR-1998 20:15:23.5 + $> dismount E: + $> exit + +What commands are supported? + A summary is:- + mount DRIVE:[,DRIVE:...] + directory [/file|/size|/date] [FILE-SPEC] + copy FILE-SPEC OUTPUT-FILE + dismount DRIVE: + search FILE-SPEC STRING + set default DIR-SPEC + show default + show time + exit + Note - DRIVE: is normally the native system drive name, + for example D: might be a CD on a PC - xxx: might be + /dev/xxx on a Unix system. + - when a list of drives is specified on the mount command + they are assumed to contain a single valid volume set + (this is not validated!!) + - file-spec is in the usual VMS syntax and may contain + wildcards (for example A:[-.*obj%%...]*abc*.obj;-2) + +Who would write this? + Me! Maybe it will become the basis of something more? If you + have suggestions or want to know more then please mail me at + paulnank@au1.ibm.com + + Thanks for listening! + Paul Nankervis