mirror of
https://github.com/open-simh/simtools.git
synced 2026-01-13 23:36:03 +00:00
FSIO: Disk and Tape container file utility
This commit is contained in:
parent
18202f1b8d
commit
5117bd4d7c
51
converters/fsio/Makefile
Normal file
51
converters/fsio/Makefile
Normal file
@ -0,0 +1,51 @@
|
||||
#CFLAGS=-O2 -Wall -Wshadow -Wextra -pedantic -Woverflow -Wstrict-overflow
|
||||
CFLAGS=-g -Wall -Wshadow -Wextra -pedantic -Woverflow -Wstrict-overflow
|
||||
DEFINES=-DDEBUG
|
||||
BIN=/usr/local/bin
|
||||
MAN=/usr/local/man/man1
|
||||
INSTALL=install
|
||||
CC=gcc
|
||||
|
||||
EXECUTABLE=fsio
|
||||
SOURCES=fsio.c declib.c tape.c dos11.c rt11.c dosmt.c local.c
|
||||
INCLUDES=fsio.h declib.h tape.h dos11.h rt11.h dosmt.h
|
||||
LIBS=-lreadline
|
||||
MANPAGE=fsio.1
|
||||
MANPAGE_DOS=fsio-dos11.1
|
||||
MANPAGE_RT=fsio-rt11.1
|
||||
MANPAGE_DOSMT=fsio-dosmt.1
|
||||
ARCHIVE=fsio.tgz
|
||||
|
||||
RELEASEFILES=$(BIN)/$(EXECUTABLE)
|
||||
RELEASEFILES+=$(MAN)/$(MANPAGE)
|
||||
RELEASEFILES+=$(MAN)/$(MANPAGE_DOS)
|
||||
RELEASEFILES+=$(MAN)/$(MANPAGE_RT)
|
||||
RELEASEFILES+=$(MAN)/$(MANPAGE_DOSMT)
|
||||
RELEASEFILES+=./fsio.txt ./fsioSimh.txt
|
||||
|
||||
$(EXECUTABLE): $(SOURCES) $(INCLUDES) Makefile
|
||||
$(CC) $(CFLAGS) $(DEFINES) -o $(EXECUTABLE) $(SOURCES) $(LIBS)
|
||||
|
||||
.phony: clean install uninstall
|
||||
|
||||
clean:
|
||||
rm -f $(EXECUTABLE)
|
||||
|
||||
install: $(EXECUTABLE) $(MANPAGE) $(MANPAGE_DOS) $(MANPAGE_RT)
|
||||
$(INSTALL) -p -m u=rx,g=rx,o=rx $(EXECUTABLE) $(BIN)
|
||||
mkdir -p $(MAN)
|
||||
$(INSTALL) -p -m u=r,g=r,o=r $(MANPAGE) $(MAN)
|
||||
$(INSTALL) -p -m u=r,g=r,o=r $(MANPAGE_DOS) $(MAN)
|
||||
$(INSTALL) -p -m u=r,g=r,o=r $(MANPAGE_RT) $(MAN)
|
||||
$(INSTALL) -p -m u=r,g=r,o=r $(MANPAGE_DOSMT) $(MAN)
|
||||
|
||||
uninstall:
|
||||
rm -f $(BIN)/$(EXECUTABLE)
|
||||
rm -f $(MAN)/$(MANPAGE)
|
||||
rm -f $(MAN)/$(MANPAGE_DOS)
|
||||
rm -f $(MAN)/$(MANPAGE_RT)
|
||||
rm -f $(MAN)/$(MANPAGE_DOSMT)
|
||||
|
||||
# This assumes that fsio has been "installed" on the current system
|
||||
archive: $(RELEASEFILES)
|
||||
tar czvPf $(ARCHIVE) $(RELEASEFILES)
|
||||
242
converters/fsio/declib.c
Normal file
242
converters/fsio/declib.c
Normal file
@ -0,0 +1,242 @@
|
||||
/*
|
||||
* Copyright (C) 2018 John Forecast. All Rights Reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY JOHN FORECAST "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Routines/data which are common to multiple DEC file systems.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <time.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "fsio.h"
|
||||
|
||||
char rad50[] = " ABCDEFGHIJKLMNOPQRSTUVWXYZ$.%0123456789";
|
||||
|
||||
char *month[12] = {
|
||||
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
||||
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
|
||||
};
|
||||
|
||||
/*
|
||||
* Table of days/month for both normal and leap years.
|
||||
*/
|
||||
unsigned short mnth[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
|
||||
unsigned short mnthl[12] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
|
||||
|
||||
/*
|
||||
* ASCII character set
|
||||
*/
|
||||
char *Ascii[128] = {
|
||||
"NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL",
|
||||
" BS", " HT", " LF", " VT", " FF", " CR", " SO", " SI",
|
||||
"DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",
|
||||
"CAN", " EM", "SUB", "ESC", " FS", " GS", " RS", " US",
|
||||
" ", " ! ", " \" ", " # ", " $ ", " % ", " & ", " \' ",
|
||||
" ( ", " ) ", " * ", " + ", " , ", " - ", " . ", " / ",
|
||||
" 0 ", " 1 ", " 2 ", " 3 ", " 4 ", " 5 ", " 6 ", " 7 ",
|
||||
" 8 ", " 9 ", " : ", " ; ", " < ", " = ", " > ", " ? ",
|
||||
" @ ", " A ", " B ", " C ", " D ", " E ", " F ", " G ",
|
||||
" H ", " I ", " J ", " K ", " L ", " M ", " N ", " O ",
|
||||
" P ", " Q ", " R ", " S ", " T ", " U ", " V ", " W ",
|
||||
" X ", " Y ", " Z ", " [ ", " \\ ", " ] ", " ^ ", " _ ",
|
||||
" ` ", " a ", " b ", " c ", " d ", " e ", " f ", " g ",
|
||||
" h ", " i ", " j ", " k ", " l ", " m ", " n ", " o ",
|
||||
" p ", " q ", " r ", " s ", " t ", " u ", " v ", " w ",
|
||||
" x ", " y ", " z ", " { ", " | ", " } ", " ~ ", "DEL"
|
||||
};
|
||||
|
||||
/*++
|
||||
* r 5 0 A s c
|
||||
*
|
||||
* Convert a 16-bit rad50 value into 3 ASCII characters.
|
||||
*
|
||||
* Inputs:
|
||||
*
|
||||
* value - rad50 value to be converted
|
||||
* outbuf - pointer to 3 character buffer to receive the
|
||||
* converted output
|
||||
*
|
||||
* Outputs:
|
||||
*
|
||||
* None
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* None
|
||||
*
|
||||
--*/
|
||||
void r50Asc(
|
||||
uint16_t value,
|
||||
char *outbuf
|
||||
)
|
||||
{
|
||||
outbuf[2] = rad50[value % 050];
|
||||
value /= 050;
|
||||
outbuf[1] = rad50[value % 050];
|
||||
outbuf[0] = rad50[value / 050];
|
||||
}
|
||||
|
||||
/*++
|
||||
* r 5 0 A s c N o S p a c e
|
||||
*
|
||||
* Convert a 16-bit rad50 value into up to 3 ASCII characters. Spaces are
|
||||
* dropped from the conversion.
|
||||
*
|
||||
* Inputs:
|
||||
*
|
||||
* value - rad50 value to be converted
|
||||
* outbuf - pointer to 3 character buffer to receive the
|
||||
* converted output
|
||||
*
|
||||
* Outputs:
|
||||
*
|
||||
* None
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* None
|
||||
*
|
||||
--*/
|
||||
void r50AscNoSpace(
|
||||
uint16_t value,
|
||||
char *outbuf
|
||||
)
|
||||
{
|
||||
uint16_t value2 = value / 050;
|
||||
|
||||
/*
|
||||
* The rad50 representation of ' ' is zero.
|
||||
*/
|
||||
if ((value2 / 050) != 0)
|
||||
*outbuf++ = rad50[value2 / 050];
|
||||
if ((value2 % 050) != 0)
|
||||
*outbuf++ = rad50[value2 % 050];
|
||||
if ((value % 050) != 0)
|
||||
*outbuf++ = rad50[value % 050];
|
||||
}
|
||||
|
||||
/*++
|
||||
* a s c R 5 0
|
||||
*
|
||||
* Convert 3 ASCII characters into a single 16-bit rad50 value. If an input
|
||||
* character is not in the rad50 character set it is quietly converted to '%'.
|
||||
*
|
||||
* Inputs:
|
||||
*
|
||||
* inbuf - pointer to the buffer with the 3 characters
|
||||
*
|
||||
* Outputs:
|
||||
*
|
||||
* None
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* rad50 value for the 3 characters
|
||||
*
|
||||
--*/
|
||||
uint16_t ascR50(
|
||||
char *inbuf
|
||||
)
|
||||
{
|
||||
uint16_t value;
|
||||
char *ptr;
|
||||
|
||||
if ((ptr = strchr(rad50, toupper(*inbuf++))) == NULL)
|
||||
ptr = strchr(rad50, '%');
|
||||
|
||||
value = (ptr - rad50) * 03100;
|
||||
|
||||
if ((ptr = strchr(rad50, toupper(*inbuf++))) == NULL)
|
||||
ptr = strchr(rad50, '%');
|
||||
|
||||
value += (ptr - rad50) * 050;
|
||||
|
||||
if ((ptr = strchr(rad50, toupper(*inbuf++))) == NULL)
|
||||
ptr = strchr(rad50, '%');
|
||||
|
||||
value += ptr - rad50;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/*++
|
||||
* d o s 1 1 D a t e
|
||||
*
|
||||
* Convert a DOS/BATCH-11 date value into an ASCII string.
|
||||
*
|
||||
* Inputs:
|
||||
*
|
||||
* value - DOS/BATCH-11 date value
|
||||
* buf - buffer to receive the string (requires 12 bytes)
|
||||
*
|
||||
* Outputs:
|
||||
*
|
||||
* None
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* Pointer to the date string
|
||||
*
|
||||
--*/
|
||||
char *dos11Date(
|
||||
uint16_t value,
|
||||
char *buf
|
||||
)
|
||||
{
|
||||
unsigned short year, doyr, leapyr;
|
||||
unsigned short *table;
|
||||
|
||||
/*
|
||||
* The DOS/BATCH-11 date format is documented as having 3 reserved bit.
|
||||
* Version 9.20C (and later?) makes use of these bits to allow dates up
|
||||
* to 2035. Unfortunately, the date input routine only allows up to 1999!
|
||||
*/
|
||||
year = 1970 + value / 1000;
|
||||
doyr = value % 1000;
|
||||
leapyr = ((year % 4) == 0) && (year != 2000);
|
||||
|
||||
table = leapyr ? mnthl : mnth;
|
||||
|
||||
/*
|
||||
* Check for valid day of year.
|
||||
*/
|
||||
if (doyr < (leapyr ? 366 : 365)) {
|
||||
int i = 0;
|
||||
|
||||
while (doyr > table[i])
|
||||
doyr -= table[i++];
|
||||
|
||||
sprintf(buf, "%2d-%s-%4d", doyr, month[i], year);
|
||||
} else strcpy(buf, "xx-yyy-xxxx");
|
||||
return buf;
|
||||
}
|
||||
40
converters/fsio/declib.h
Normal file
40
converters/fsio/declib.h
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (C) 2018 John Forecast. All Rights Reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY JOHN FORECAST "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef __DECLIB_H__
|
||||
#define __DECLIB_H__
|
||||
|
||||
extern char rad50[];
|
||||
extern char *month[];
|
||||
extern char *Ascii[];
|
||||
|
||||
extern void r50Asc(uint16_t, char *);
|
||||
extern void r50AscNoSpace(uint16_t, char *);
|
||||
extern uint16_t ascR50(char *);
|
||||
extern char *dos11Date(uint16_t, char *);
|
||||
|
||||
#endif
|
||||
2523
converters/fsio/dos11.c
Normal file
2523
converters/fsio/dos11.c
Normal file
File diff suppressed because it is too large
Load Diff
292
converters/fsio/dos11.h
Normal file
292
converters/fsio/dos11.h
Normal file
@ -0,0 +1,292 @@
|
||||
/*
|
||||
* Copyright (C) 2018 John Forecast. All Rights Reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY JOHN FORECAST "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef __DOS11_H__
|
||||
#define __DOS11_H__
|
||||
|
||||
/*
|
||||
* General disk layout:
|
||||
*
|
||||
* Block
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* 0 | Reserved for Bootstrap |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* 1 | MFD Block #1 |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* 2 | UFD Block #1 |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* ... | |
|
||||
* | User linked files |
|
||||
* | & |
|
||||
* | other UFD blocks |
|
||||
* | |
|
||||
* |-- --|
|
||||
* | User contiguous files |
|
||||
* | |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* X-n | MFD Block #2 |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* X-n-1 | Bitmap Block #1 |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* ... | |
|
||||
* | |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* X | Bitmap Block #n |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
*
|
||||
* MFD Block 1:
|
||||
*
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* | Block # of MFD Block 2 |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* | Interleave factor |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* | Bitmap start block # |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* | Bitmap #1 block # |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* | Bitmap #2 block # |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* | |
|
||||
* | ... |
|
||||
* | |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* | Bitmap #N block # |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* | 0 |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* | |
|
||||
*
|
||||
* MFD Block 2 - N:
|
||||
*
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* | Link to next MFD block or 0 |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* | Group code | User code |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* | UFD start block # |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* | # of words in UFD entry |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* | 0 |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* | Repeat above 4 words |
|
||||
* | for each UFD |
|
||||
* | |
|
||||
*
|
||||
* UFD Block:
|
||||
*
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* | Link to next UFD block or 0 |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* | File |
|
||||
* +- -+
|
||||
* | name |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* | Extension |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* |Typ| Rsvd | Creation Date |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* | Next free byte |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* | Start block # |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* | Length (in # of blocks) |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* | Last block written |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* |LCK| Usage count | Protection code |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
*
|
||||
* Bitmap Block:
|
||||
*
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* | Link to next bitmap block |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* | Map # |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* | # of words of map |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* | Link to first bitmap block |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* | Map for blocks 0 - 17 |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* | Map for blocks 20 - 37 |
|
||||
* | ... |
|
||||
* | |
|
||||
*/
|
||||
|
||||
/*
|
||||
* The MFD and UFD directories can be treated as an array of 16-bit values.
|
||||
* The following offsets describe each structure.
|
||||
*/
|
||||
#define BOOT_BLOCK 0 /* Reserved for bootstrap */
|
||||
#define MFD1_BLOCK 1 /* MFD always at block 1*/
|
||||
|
||||
#define MFD1_MFD2BLOCK 0
|
||||
#define MFD1_INTERLEAVE 1
|
||||
#define MFD1_BMSTART 2
|
||||
#define MFD1_BM1 3
|
||||
|
||||
#define MFD2_LINK 0
|
||||
#define MFD2_HEADER 1
|
||||
|
||||
#define MFD2_UFDUIC 0
|
||||
#define MFD2_UFDSTART 1
|
||||
#define MFD2_UFDSIZE 2
|
||||
#define MFD2_UFDZERO 3
|
||||
#define MFD2_SIZE 4
|
||||
|
||||
#define UFD_LINK 0
|
||||
#define UFD_HEADER 1
|
||||
|
||||
#define UFD_FILENAME 0
|
||||
#define UFD_EXTENSION 2
|
||||
#define UFD_CREATION 3
|
||||
#define UFD_TYPE 0100000
|
||||
#define UFD_TYPELINKED 0000000
|
||||
#define UFD_TYPECONTIGUOUS 0100000
|
||||
#define UFD_DATE 0077777
|
||||
#define UFD_NEXTFREEBYTE 4
|
||||
#define UFD_FILESTART 5
|
||||
#define UFD_FILELENGTH 6
|
||||
#define UFD_LASTBLOCKWRITTEN 7
|
||||
#define UFD_LUP 8
|
||||
#define UFD_LOCK 0100000
|
||||
#define UFD_USAGE 0077400
|
||||
#define UFD_PROT 0000377
|
||||
#define UFD_LEN 9 /* 9 word in each entry */
|
||||
|
||||
#define MAP_LINK 0
|
||||
#define MAP_MAP 1
|
||||
#define MAP_WORDS 2
|
||||
#define MAP_FIRST 3
|
||||
#define MAP_BMSTART 4
|
||||
#define MAP_LEN 60 /* 60 words in each entry */
|
||||
#define MAP_BLOCKS (MAP_LEN * 16)
|
||||
|
||||
#define FILE_LINK 0
|
||||
|
||||
/*
|
||||
* Block sizes for each supported disk drive
|
||||
*/
|
||||
#define BLOCKSIZE_RC11 64
|
||||
#define BLOCKSIZE_RF11 64
|
||||
#define BLOCKSIZE_RK11 256
|
||||
#define BLOCKSIZE_RP03 512
|
||||
|
||||
/*
|
||||
* Max # of UIC's (UFDs) for each supported disk drive
|
||||
*/
|
||||
#define UICCOUNT_RC11 15
|
||||
#define UICCOUNT_RF11 15
|
||||
#define UICCOUNT_RK11 63
|
||||
#define UICCOUNT_RP03 127
|
||||
|
||||
/*
|
||||
* Compute end of directory block, given the size of each directory entry.
|
||||
* This macro is good for both MFDs and UFDs.
|
||||
*/
|
||||
#define EODIR(m, sz) ((m->blocksz / 2) - (sz - 1))
|
||||
|
||||
/*
|
||||
* The logical block size will depend on the type of the disks. Disks smaller
|
||||
* than a RK05 (RS11/RS64) will use 64 word blocks while disks larger than
|
||||
* a RK05 (RP03) will use 512 word blocks. The default will be for an 256
|
||||
* word blocks for a RK05.
|
||||
*/
|
||||
#define DISKSIZE_RK05 4800
|
||||
|
||||
/*
|
||||
* Structure to describe a filename and associated UIC. Asterisks may be used
|
||||
* as wild card characters for the 4 components of a filename; name, extension,
|
||||
* group number and user number.
|
||||
*/
|
||||
struct dos11FileSpec {
|
||||
uint8_t flags; /* Wild card indicators */
|
||||
uint16_t name[2]; /* File name */
|
||||
uint16_t ext; /* Extension */
|
||||
unsigned char user; /* User number */
|
||||
unsigned char group; /* Group number */
|
||||
};
|
||||
#define DOS11_WC_NAME 0001 /* Wild card name */
|
||||
#define DOS11_WC_EXT 0002 /* Wild card extension */
|
||||
#define DOS11_WC_GROUP 0004 /* Wild card group number */
|
||||
#define DOS11_WC_USER 0010 /* Wild card user number */
|
||||
|
||||
#define DOS11_M_NONE 0000 /* Wild cards not allowed */
|
||||
#define DOS11_M_ALLOW 0001 /* Wild cards allowed */
|
||||
#define DOS11_M_NONAME 0002 /* Wild cards allowed */
|
||||
/* If no filename + extension */
|
||||
/* present, default to *.* */
|
||||
/*
|
||||
* Structure to define an open file. This is a DOS-11 UFD entry along with
|
||||
* sufficient information to be able to write the directory entry back
|
||||
* to disk.
|
||||
*/
|
||||
struct dos11OpenFile {
|
||||
uint16_t name[2]; /* File name */
|
||||
uint16_t ext; /* Extension */
|
||||
uint16_t creation; /* Type + creation date */
|
||||
uint16_t nfb; /* Next free byte */
|
||||
uint16_t start; /* Start block # */
|
||||
uint16_t length; /* Length in blocks */
|
||||
uint16_t last; /* Last block written */
|
||||
uint16_t lup; /* Lock, usage + protection */
|
||||
/* End of directory entry */
|
||||
uint16_t ufdblk; /* UFD block # */
|
||||
uint16_t ufdoffset; /* Offset within UFD */
|
||||
/* Start of read/write info */
|
||||
enum openMode mode; /* Open mode (read/write) */
|
||||
struct mountedFS *mount; /* Mounted file system descriptor */
|
||||
char *buffer; /* Private buffer for file I/O */
|
||||
uint16_t current; /* Current block */
|
||||
uint16_t nab; /* Next available byte */
|
||||
uint16_t eob; /* End of buffer */
|
||||
};
|
||||
|
||||
/*
|
||||
* DOS-11 specific data area. Some fields are sized for the worst case -
|
||||
* RP03 disk pack with 65535 blocks of 1024 bytes each.
|
||||
*/
|
||||
struct DOS11data {
|
||||
unsigned int blocks; /* # of blocks in file system */
|
||||
uint16_t bitmaps; /* # of bitmaps */
|
||||
uint16_t bmblk[128]; /* Bitmap block addresses */
|
||||
uint16_t bmindex; /* Current bitmap in buffer */
|
||||
uint16_t bmscan; /* Start bitmap scans here */
|
||||
uint8_t bmdirty; /* 0 => clean, 1 => dirty */
|
||||
uint16_t bmbuf[512]; /* Buffer for bitmap access */
|
||||
uint16_t buf[512]; /* Disk buffer */
|
||||
/*
|
||||
* Settable parameters
|
||||
*/
|
||||
uint8_t group; /* Default group # */
|
||||
uint8_t user; /* Default user # */
|
||||
};
|
||||
|
||||
#endif
|
||||
1321
converters/fsio/dosmt.c
Normal file
1321
converters/fsio/dosmt.c
Normal file
File diff suppressed because it is too large
Load Diff
101
converters/fsio/dosmt.h
Normal file
101
converters/fsio/dosmt.h
Normal file
@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright (C) 2018 John Forecast. All Rights Reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY JOHN FORECAST "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef __DOSMT_H__
|
||||
#define __DOSMT_H__
|
||||
#include "tape.h"
|
||||
|
||||
/*
|
||||
* DOS-11 magtapes contain data records of 512 bytes each.
|
||||
*/
|
||||
#define DOSMTRCLNT 512
|
||||
|
||||
/*
|
||||
* DOS/BATCH-11 magtape file header.
|
||||
*/
|
||||
struct dosmthdr {
|
||||
uint16_t fname[2]; /* first 6 chars of filename (RAD50) */
|
||||
uint16_t ext; /* 3 char file extension (RAD50) */
|
||||
uint8_t prog; /* programmer # (octal) */
|
||||
uint8_t proj; /* project # (octal) */
|
||||
uint16_t prot; /* protection code (octal) */
|
||||
uint16_t date; /* (year-1970) * 1000 + day of year */
|
||||
uint16_t fname3; /* optional, char 7 - 9 of name */
|
||||
};
|
||||
|
||||
/*
|
||||
* Structure to describe a filename and associated UIC. Asterisks may be used
|
||||
* as wild card characters for the 4 components of a filename; name, extension,
|
||||
* group number and user number.
|
||||
*/
|
||||
struct dosmtFileSpec {
|
||||
uint8_t flags; /* Wild card indicators */
|
||||
uint16_t name[3]; /* File name */
|
||||
uint16_t ext; /* Extension */
|
||||
unsigned char proj; /* Project number */
|
||||
unsigned char prog; /* Programmer number */
|
||||
};
|
||||
#define DOSMT_WC_NAME 0001 /* Wild card name */
|
||||
#define DOSMT_WC_EXT 0002 /* Wild card extension */
|
||||
#define DOSMT_WC_PROJ 0004 /* Wild card project number */
|
||||
#define DOSMT_WC_PROG 0010 /* Wild card programmer number */
|
||||
|
||||
#define DOSMT_M_NONE 0000 /* Wild cards not allowed */
|
||||
#define DOSMT_M_ALLOW 0001 /* Wild cards allowed */
|
||||
#define DOSMT_M_NONAME 0002 /* Wild cards allowed */
|
||||
/* If no filename + extension */
|
||||
/* present, default to *.*[*,*] */
|
||||
|
||||
/*
|
||||
* Structure to define an open file.
|
||||
*/
|
||||
struct dosmtOpenFile {
|
||||
enum openMode mode; /* Open mode (read/write) */
|
||||
struct mountedFS *mount; /* Mounted file system descriptor */
|
||||
char buf[DOSMTRCLNT];/* Private buffer for file I/O */
|
||||
uint16_t nextb; /* Next byte to use */
|
||||
uint8_t tm; /* Tape mark has been read */
|
||||
uint8_t error; /* Error has been detected */
|
||||
};
|
||||
|
||||
/*
|
||||
* DOS-11 magtape specific data area.
|
||||
*/
|
||||
struct DOSMTdata {
|
||||
uint8_t buf[DOSMTRCLNT];
|
||||
off_t eot; /* Logical end-of-tape */
|
||||
|
||||
/*
|
||||
* Settable parameters
|
||||
*/
|
||||
uint8_t proj; /* project # */
|
||||
uint8_t prog; /* programmer # */
|
||||
uint8_t prot; /* protection code */
|
||||
#define FS_DOSMTEXT 0x0100 /* Write extended file headers */
|
||||
};
|
||||
|
||||
#endif
|
||||
50
converters/fsio/fsio-dos11.1
Normal file
50
converters/fsio/fsio-dos11.1
Normal file
@ -0,0 +1,50 @@
|
||||
.TH FSIO-DOS11 1 "December 28,2018" "FFS I/O - DOS-11"
|
||||
.SH NAME
|
||||
fsio-dos11 \- Foreign File System I/O - DOS-11
|
||||
.br
|
||||
.SH DESCRIPTION
|
||||
\fBfsio\fP allows access to DOS-11 file systems using the file system type
|
||||
"\fIdos11\fP"
|
||||
.br
|
||||
.SH WILDCARD CHARACTERS
|
||||
The wildcard character \fI'*'\fP may be used to match filename, extension,
|
||||
group number and user number. Wildcard characters are only valid with the
|
||||
\fIdir\fP command.
|
||||
.br
|
||||
.SH NEWFS OPERATION
|
||||
\fInewfs\fP creates a blank RK05 image (2.5MB, 4800 blocks) with no UFD
|
||||
entries.
|
||||
.SH SET OPERATION
|
||||
The following \fIset\fP commands are supported:
|
||||
.br
|
||||
.TP
|
||||
.B "\fIuic\fP [group,user]"
|
||||
Sets the default UIC for file access (was [1,1] after mount).
|
||||
.br
|
||||
.RS
|
||||
.RS
|
||||
.B "\fIgroup\fP \- Group number (octal 1 - 377)"
|
||||
.br
|
||||
.B "\fIuser\fP \- User number (octal 1 - 377)"
|
||||
.br
|
||||
.RE
|
||||
.RE
|
||||
.TP
|
||||
.B "\fIufd\fP [group,user]"
|
||||
Creates an empty UFD and sets default UIC for file access.
|
||||
.br
|
||||
.RS
|
||||
.RS
|
||||
.B "\fIgroup\fP \- Group number (octal 1 - 377)"
|
||||
.br
|
||||
.B "\fIuser\fP \- User number (octal 1 - 377)"
|
||||
.br
|
||||
.RE
|
||||
.RE
|
||||
.SH SEE ALSO
|
||||
.BR fsio (1),
|
||||
.BR fsio-rt11 (1)
|
||||
.BR fsio-dosmt (1)
|
||||
.SH AUTHOR
|
||||
John Forecast, <john@forecast.name>
|
||||
.br
|
||||
110
converters/fsio/fsio-dosmt.1
Normal file
110
converters/fsio/fsio-dosmt.1
Normal file
@ -0,0 +1,110 @@
|
||||
.TH FSIO-DOSMT 1 "January 28,2019" "FFS I/O - DOS-11 magtape"
|
||||
.SH NAME
|
||||
fsio-dosmt \- Foreign File System I/O - DOS-11 magtape
|
||||
.br
|
||||
.SH DESCRIPTION
|
||||
\fBfsio\fP allows access to DOS-11 magtapes using the file system type
|
||||
"\fIdosmt\fP"
|
||||
.br
|
||||
.SH WILDCARD CHARACTERS
|
||||
The wildcard character \fI'*'\fP may be used to match filename, extension,
|
||||
group number and user number. Wildcard characters may be used with the
|
||||
\fIdir\fP command to limit the number of files being displayed. They may also
|
||||
be used with commands to read files; \fIdump\fP, \fItype\fP and \fIcopy\fP
|
||||
(only the source file for \fIcopy\fP), in which case the next file which
|
||||
matches the wildcard character(s) will be used for input. As a consequence
|
||||
of this, the empty filename may be used to select the next file on the tape,
|
||||
so:
|
||||
.RS
|
||||
|
||||
fsio> type mt:
|
||||
.RE
|
||||
|
||||
will type the next file on the tape.
|
||||
.br
|
||||
.SH MOUNT OPERATION
|
||||
DOS/BATCH-11 defined magtape headers to be 14 bytes long with 2 bytes unused.
|
||||
Some tapes use these unused bytes to add an additional 3 characters to the
|
||||
filename (e.g. ABCDEFGHI.EXT rather than ABCDEF.EXT). By default, fsio will
|
||||
ignore these unused bytes. If the \fI-x\fP switch is used on the \fImount\fP
|
||||
command, fsio will make use of the extra 3 characters on file lookup,
|
||||
directory listing and file creation.
|
||||
.SH NEWFS OPERATION
|
||||
\fInewfs\fP creates an empty (zero length) file.
|
||||
.SH SET OPERATION
|
||||
The following \fIset\fP commands are supported:
|
||||
.br
|
||||
.TP
|
||||
.B "\fIuic\fP [proj,prog]"
|
||||
Sets the default UIC for file access (was [1,1] after mount).
|
||||
.br
|
||||
.RS
|
||||
.RS
|
||||
.B "\fIproj\fP \- Project number (octal 1 - 377)"
|
||||
.br
|
||||
.B "\fIprog\fP \- Programmer number (octal 1 - 377)"
|
||||
.br
|
||||
.RE
|
||||
.RE
|
||||
.TP
|
||||
.B "\fIprot\fP <code>"
|
||||
Set the default protection code when writing new files to magtape.
|
||||
.br
|
||||
.RS
|
||||
.RS
|
||||
.B "\fIprot\fP \- Protection code (octal 0 - 377)"
|
||||
.br
|
||||
.RE
|
||||
.RE
|
||||
.SH INFO OPERATION
|
||||
\fIinfo\fP displays where the tape is currently positioned. If the tape is
|
||||
not positioned at the end and it is not an empty tape, the name of the next
|
||||
file after the current position will be displayed.
|
||||
.SH NOTES
|
||||
DOS-11 magtapes differ from disk-based file systems in a number of ways:
|
||||
.br
|
||||
.RS
|
||||
1. Filenames are not unique on a magtape.
|
||||
.br
|
||||
2. The tape has to be positioned before writing a new file to
|
||||
avoid over-writing an existing file.
|
||||
.br
|
||||
.RE
|
||||
|
||||
Assuming a magtape is mounted on mt: and has 5 files on it:
|
||||
.br
|
||||
|
||||
The sequence:
|
||||
.br
|
||||
.RS
|
||||
|
||||
fsio> rewind mt:
|
||||
.br
|
||||
fsio> copy -a a.b mt:c.d
|
||||
.br
|
||||
.RE
|
||||
|
||||
will result in the tape containing a single file (c.d), while the sequence:
|
||||
.br
|
||||
.RS
|
||||
|
||||
fsio> eom mt:
|
||||
.br
|
||||
fsio> copy -a a.b mt:c.d
|
||||
.br
|
||||
.RE
|
||||
|
||||
will result in the tape containing 6 files (the original 5 followed by c.d).
|
||||
.br
|
||||
|
||||
By using skipf/skipr commands it is possible to position the tape just past
|
||||
the end of any specific file (see info command for more details on how to
|
||||
determine the current tape position).
|
||||
.br
|
||||
.SH SEE ALSO
|
||||
.BR fsio (1),
|
||||
.BR fsio-dos11 (1)
|
||||
.BR fsio-rt11 (1)
|
||||
.SH AUTHOR
|
||||
John Forecast, <john@forecast.name>
|
||||
.br
|
||||
42
converters/fsio/fsio-rt11.1
Normal file
42
converters/fsio/fsio-rt11.1
Normal file
@ -0,0 +1,42 @@
|
||||
.TH FSIO-RT11 1 "December 28,2018" "FFS I/O - RT-11"
|
||||
.SH NAME
|
||||
fsio-rt11 \- Foreign File System I/O - RT-11
|
||||
.br
|
||||
.SH DESCRIPTION
|
||||
\fBfsio\fP allows access to RT-11 file systems using the file system type
|
||||
"\fIrt11\fP"
|
||||
.br
|
||||
.SH WILDCARD CHARACTERS
|
||||
The wildcard character \fI'%'\fP may be used to match a single character in a
|
||||
filename or type. The wildcard character \fI'*'\fP may be used to match
|
||||
zero or more characters in a filename or type. Wildcard characters are only
|
||||
valid with the \fIdir\fP command.
|
||||
.br
|
||||
.SH NEWFS OPERATION
|
||||
\fInewfs\fP creates a blank MSCP image (32MB, 65535 blocks) with a single
|
||||
partition which can be accessed via the DU device (rq in SIMH). If the
|
||||
\fI"-t type"\fP switch is present, a smaller container file will be created
|
||||
depending on the type of device specified:
|
||||
.br
|
||||
.TP
|
||||
\fIrl02\fP \- RL02 image (10MB, 20480 blocks)
|
||||
.br
|
||||
.TP
|
||||
\fIrx20\fP \- RX20 image (512KB, 1024 blocks)
|
||||
.br
|
||||
.SH COPY OPERATION
|
||||
When copying in ASCII mode, \fBfsio\fP will normally write ^Z (octal 032) to
|
||||
indicate the end-of-file. Some utilities, such as FLX on RSX-11, cannot
|
||||
handle ^Z in the middle of a formatted ASCII file. The \fI"-p"\fP switch
|
||||
may be used on a copy operation to skip writing the ^Z and pad the file with
|
||||
NULLs up to the next block boundary if this occurs.
|
||||
.br
|
||||
.SH SET OPERATION
|
||||
No \fIset\fP commands are currently supported.
|
||||
.SH SEE ALSO
|
||||
.BR fsio (1),
|
||||
.BR fsio-dos11 (1)
|
||||
.BR fsio-dosmt (1)
|
||||
.SH AUTHOR
|
||||
John Forecast, <john@forecast.name>
|
||||
.br
|
||||
334
converters/fsio/fsio.1
Normal file
334
converters/fsio/fsio.1
Normal file
@ -0,0 +1,334 @@
|
||||
.TH FSIO 1 "December 25,2018" "Foreign File System I/O"
|
||||
.SH NAME
|
||||
fsio \- Foreign File System I/O
|
||||
.SH SYNOPSIS
|
||||
.B fsio
|
||||
[
|
||||
.B \-qv
|
||||
]
|
||||
[
|
||||
.I cmdfile
|
||||
]
|
||||
.br
|
||||
.SH DESCRIPTION
|
||||
\fBfsio\fP is a utility for manipulating foreign file systems within container
|
||||
files used by various emulators such as
|
||||
.B SIMH.
|
||||
|
||||
If cmdfile is given, commands will be read and executed from the command file
|
||||
otherwise it will prompt the user for commands with \fBfsio> \fP
|
||||
.br
|
||||
.TP
|
||||
\fB-q\fP - Be quiet, do not output unsolicited text during processing
|
||||
.TP
|
||||
\fB-v\fP - Echo each command as it is read from a command file
|
||||
.br
|
||||
.TP
|
||||
Each command occupies one line and has a common format:
|
||||
.br
|
||||
.RS
|
||||
.TP
|
||||
verb [switches] args ...
|
||||
.RE
|
||||
.TP
|
||||
The following verbs are supported:
|
||||
|
||||
.br
|
||||
.B "\fImount\fP \- make a container file available to fsio"
|
||||
.br
|
||||
.B "\fIumount\fP \- remove knowledge of a container file from fsio"
|
||||
.br
|
||||
.B "\fInewfs\fP \- create and new container and empty file system"
|
||||
.br
|
||||
.B "\fIset\fP \- set parameters on a mounted file system"
|
||||
.br
|
||||
.B "\fIinfo\fP \- display information about the container file system"
|
||||
.br
|
||||
.B "\fIdir\fP \- list a directory"
|
||||
.br
|
||||
.B "\fIdump\fP \- dump a file in hex or octal"
|
||||
.br
|
||||
.B "\fIcopy\fP \- copy a single file"
|
||||
.br
|
||||
.B "\fItype\fP \- type a file on the terminal"
|
||||
.br
|
||||
.B "\fIdelete\fP \- delete a file"
|
||||
.br
|
||||
.B "\fIstatus\fP \- display currently mounted file systems"
|
||||
.br
|
||||
.B "\fIdo\fP \- echo and execute commands from a file"
|
||||
.br
|
||||
.B "\fIhelp\fP \- display help on using fsio"
|
||||
.br
|
||||
.B "\fIexit\fP \- terminate fsio (quit is an alias for exit)"
|
||||
.br
|
||||
.TP
|
||||
The following commands are only accepted by file systems which are on magtape devices:
|
||||
|
||||
.br
|
||||
.B "\fIrewind\fP \- position the tape to the start of the data stream"
|
||||
.br
|
||||
.B "\fIeom\fP \- position the tape to the end of the data stream"
|
||||
.br
|
||||
.B "\fIskipf\fP \- position the tape by skipping forward over files"
|
||||
.br
|
||||
.B "\fIskipr\fP \- position the tape by skipping backward over files"
|
||||
.br
|
||||
.SH COMMANDS
|
||||
.TP
|
||||
.B "\fImount\fP [-drx] dev[:] file type"
|
||||
Make the container file available to fsio.
|
||||
.br
|
||||
.RS
|
||||
.RS
|
||||
.B "\fI\-d\fP \- generate debug output on stdout"
|
||||
.br
|
||||
.B " Use environment variable \fIFSioDebugLog\fP to"
|
||||
.br
|
||||
.B " override stdout"
|
||||
.br
|
||||
.B " Only available if built with DEBUG enabled"
|
||||
.br
|
||||
.B "\fI\-r\fP \- mount file system read-only"
|
||||
.br
|
||||
.B "\fI\-x\fP \- dosmt will use extended filenames when writing"
|
||||
.br
|
||||
.B "\fIdev[:]\fP \- user supplied name for the mount"
|
||||
.br
|
||||
.B "\fIfile\fP \- name of the container file"
|
||||
.br
|
||||
.B "\fItype\fP \- type of container file system"
|
||||
.br
|
||||
.RE
|
||||
.RE
|
||||
.TP
|
||||
.B "\fIumount\fP dev[:]"
|
||||
Remove knowledge of the container file from fsio.
|
||||
.br
|
||||
.RS
|
||||
.RS
|
||||
.B "\fIdev[:]\fP \- name supplied on a previous mount"
|
||||
.RE
|
||||
.RE
|
||||
.TP
|
||||
.B "\fInewfs\fP [-t type] file type"
|
||||
Create an new container with an empty file system.
|
||||
.br
|
||||
.RS
|
||||
.RS
|
||||
.B "\fI\-t type\fP \- use alternate, file-system dependent size"
|
||||
.br
|
||||
.B "\fIfile\fP \- name of the container file"
|
||||
.br
|
||||
.B "\fItype\fP \- type of container file system"
|
||||
.br
|
||||
.RE
|
||||
.RE
|
||||
.TP
|
||||
.B "\fIset\fP dev: args ..."
|
||||
Set parameters on a mounted file system.
|
||||
.br
|
||||
.RS
|
||||
.RS
|
||||
.B "\fIdev:\fP \- name supplied on a previous mount"
|
||||
.br
|
||||
.B "\fIargs ...\fP\- arguments are passed on to the file system"
|
||||
.br
|
||||
.RE
|
||||
.RE
|
||||
.TP
|
||||
.B "\fIinfo\fP dev:"
|
||||
Display information about the file system(s) within the container file.
|
||||
.br
|
||||
.RS
|
||||
.RS
|
||||
.B "\fIdev:\fP \- name supplied on a previous mount"
|
||||
.RE
|
||||
.RE
|
||||
.TP
|
||||
.B "\fIdir\fP [-fn] dev:dirspec"
|
||||
List the contents of a specific directory.
|
||||
.br
|
||||
.RS
|
||||
.RS
|
||||
.B "\fI\-f\fP \- display a full (vs. brief) directory"
|
||||
.br
|
||||
.B "\fI\-n\fP \- don't rewind tape before listing directory"
|
||||
.br
|
||||
.B "\fIdev:\fP \- name supplied on a previous mount"
|
||||
.br
|
||||
.B "\fIdirspec\fP \- filespec to display, may include wildcards"
|
||||
.br
|
||||
.RE
|
||||
.RE
|
||||
.TP
|
||||
.B "\fIdump\fP [-bcdnwx] dev:filespec"
|
||||
Dump the contents of the file in octal, hex or characters.
|
||||
.br
|
||||
.RS
|
||||
.RS
|
||||
.B "\fI\-b\fP \- dump byte (8-bits) at a time"
|
||||
.br
|
||||
.B "\fI\-c\fP \- dump in character format"
|
||||
.br
|
||||
.B "\fI\-d\fP \- dump double-word (32-bits) at a time"
|
||||
.br
|
||||
.B "\fI\-w\fP \- dump word (16-bits) at a time"
|
||||
.br
|
||||
.B "\fI\-x\fP \- dump in hex format (default is octal)"
|
||||
.br
|
||||
.B "\fI\-n\fP \- don't rewind magtape before looking for file"
|
||||
.br
|
||||
.B "\fIdev:\fP \- name supplied on a previous mount"
|
||||
.br
|
||||
.B "\fIdirspec\fP \- filespec to dump"
|
||||
.br
|
||||
.RE
|
||||
.RE
|
||||
.TP
|
||||
.B "\fIcopy\fP [-anpc blks] dev1:srcfile dev2:dstfile"
|
||||
Copy a file.
|
||||
.br
|
||||
.RS
|
||||
.RS
|
||||
.B "\fI\-a\fP \- copy in ASCII mode (translates line endings)"
|
||||
.br
|
||||
.B "\fI\-p\fP \- pad the file with NULLs"
|
||||
.br
|
||||
.B "\fI\-n\fP \- don't rewind magtape before looking for input file"
|
||||
.br
|
||||
.B "\fI\-c blks\fP \- make contiguous file of specified size"
|
||||
.br
|
||||
.B "\fIdev1:\fP \- name supplied on a previous mount"
|
||||
.br
|
||||
.B "\fIsrcfile\fP \- source file to copy"
|
||||
.br
|
||||
.B "\fIdev2:\fP \- name supplied on a previous mount"
|
||||
.br
|
||||
.B "\fIdstfile\fP \- destination file to copy"
|
||||
.br
|
||||
.RE
|
||||
.RE
|
||||
.TP
|
||||
.B "\fItype\fP [-n] dev:filespec"
|
||||
Types the contents of the file on stdout.
|
||||
.br
|
||||
.RS
|
||||
.RS
|
||||
.B "\fI\-n\fP \- don't rewind magtape before looking for file"
|
||||
.br
|
||||
.B "\fIdev:\fP \- name supplied on a previous mount"
|
||||
.br
|
||||
.B "\fIfilespec\fP\- filespec to type"
|
||||
.br
|
||||
.RE
|
||||
.RE
|
||||
.TP
|
||||
.B "\fIdelete\fP dev:filespec"
|
||||
Deletes the specified file.
|
||||
.br
|
||||
.RS
|
||||
.RS
|
||||
.B "\fIdev:\fP \- name supplied on a previous mount"
|
||||
.br
|
||||
.B "\fIfilespec\fP\- filespec to delete"
|
||||
.br
|
||||
.RE
|
||||
.RE
|
||||
.TP
|
||||
.B "\fIstatus\fP"
|
||||
Displays the currently mounted file system(s).
|
||||
.br
|
||||
.TP
|
||||
.B "\fIdo\fP [-q] cmdFile"
|
||||
Echo and execute commands from a file.
|
||||
.br
|
||||
.RS
|
||||
.RS
|
||||
.B "\fI\-q\fP \- don't echo commands as they are read"
|
||||
.br
|
||||
.B "\fIcmdFile\fP \- file containing fsio commands"
|
||||
.br
|
||||
.RE
|
||||
.RE
|
||||
.TP
|
||||
.B "\fIhelp\fP"
|
||||
Displays help text on stdout.
|
||||
.br
|
||||
.TP
|
||||
.B "\fIexit\fP"
|
||||
Causes fsio to exit (the quit command has the same effect).
|
||||
.br
|
||||
.TP
|
||||
.B "\fIrewind\fP dev:"
|
||||
Positions the device to the start of the tape.
|
||||
.br
|
||||
.RS
|
||||
.RS
|
||||
.B "\fIdev:\fP \- name supplied on a previous mount"
|
||||
.br
|
||||
.RE
|
||||
.RE
|
||||
.TP
|
||||
.B "\fIeom\fP dev:"
|
||||
Positions the device to the end of the tape.
|
||||
.br
|
||||
.RS
|
||||
.RS
|
||||
.B "\fIdev:\fP \- name supplied on a previous mount"
|
||||
.br
|
||||
.RE
|
||||
.RE
|
||||
.TP
|
||||
.B "\fIskipf\fP dev: n"
|
||||
Positions the device by skipping forward over files.
|
||||
.br
|
||||
.RS
|
||||
.RS
|
||||
.B "\fIdev:\fP \- name supplied on a previous mount"
|
||||
.br
|
||||
.B "\fIn\fP \- # of files to skip (must be > 0)"
|
||||
.br
|
||||
.RE
|
||||
.RE
|
||||
.TP
|
||||
.B "\fIskipr\fP dev: n"
|
||||
Positions the device by skipping backward over files.
|
||||
.br
|
||||
.RS
|
||||
.RS
|
||||
.B "\fIdev:\fP \- name supplied on a previous mount"
|
||||
.br
|
||||
.B "\fIn\fP \- # of files to skip (must be > 0)"
|
||||
.br
|
||||
.RE
|
||||
.RE
|
||||
.SH NOTES
|
||||
If the "\fIdev:\fP" prefix is not present on a file specification, a file in
|
||||
the host file system is used. It is also possible to use the "\fIlocal:\fP"
|
||||
prefix to reference local files.
|
||||
|
||||
.br
|
||||
The -c switch on the copy command is used to determine the number of
|
||||
contiguous blocks allocated to the destination file before starting the copy.
|
||||
This function depends on the value of blks:
|
||||
|
||||
.br
|
||||
.B "\fI0\fP \- Use size of source file, if 0 then default to 1 block"
|
||||
.br
|
||||
.B "\fI!=0\fP \- Use larger of blks and size of the source file"
|
||||
.br
|
||||
.SH SUPPORTED FILESYSTEMS
|
||||
.B "\fIdos11\fP \- DOS/BATCH-11 on RF11, RK05 or RP03"
|
||||
.br
|
||||
.B "\fIrt11\fP \- RT-11 including large drives with multiple partitions"
|
||||
.br
|
||||
.B "\fIdosmt\fP \- container file in DOS-11 magtape format"
|
||||
.br
|
||||
.SH SEE ALSO
|
||||
.BR fsio-dos11 (1),
|
||||
.BR fsio-rt11 (1)
|
||||
.BR fsio-dosmt (1)
|
||||
.SH AUTHOR
|
||||
John Forecast, <john@forecast.name>
|
||||
.br
|
||||
1983
converters/fsio/fsio.c
Normal file
1983
converters/fsio/fsio.c
Normal file
File diff suppressed because it is too large
Load Diff
166
converters/fsio/fsio.h
Normal file
166
converters/fsio/fsio.h
Normal file
@ -0,0 +1,166 @@
|
||||
/*
|
||||
* Copyright (C) 2018 John Forecast. All Rights Reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY JOHN FORECAST "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __FSIO_H__
|
||||
#define __FSIO_H__
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include "declib.h"
|
||||
|
||||
/*
|
||||
* Mode for open files
|
||||
*/
|
||||
enum openMode { M_RD, M_WR };
|
||||
|
||||
#include "dos11.h"
|
||||
#include "rt11.h"
|
||||
#include "dosmt.h"
|
||||
|
||||
/*
|
||||
* All of the supported file systems are natively little endian so we only
|
||||
* need a subset of the endian support macros/routines.
|
||||
*/
|
||||
#if defined(__APPLE__)
|
||||
#include <libkern/OSByteOrder.h>
|
||||
|
||||
#define htole16(x) OSSwapHostToLittleInt16(x)
|
||||
#define le16toh(x) OSSwapLittleToHostInt16(x)
|
||||
|
||||
#define htole32(x) OSSwapHostToLittleInt32(x)
|
||||
#define le32toh(x) OSSwapLittleToHostInt32(x)
|
||||
#elif defined(__linux__)
|
||||
#include <endian.h>
|
||||
#elif defined(__FreeBSD__) || defined(__NetBSD__)
|
||||
#include <sys/endian.h>
|
||||
|
||||
#define le16toh(x) letoh16(x)
|
||||
|
||||
#define le32toh(x) letoh32(x)
|
||||
#elif defined(__OpenBSD__)
|
||||
#include <sys/endian.h>
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define UNUSED(x) UNUSED_ ## x __attribute__((__unused__))
|
||||
#else
|
||||
#define UNUSED(x) UNUSED_ ## x
|
||||
#endif
|
||||
|
||||
#define MAX_DEVLEN 16
|
||||
|
||||
#if defined(__linux__)
|
||||
#define OPTIONS(s) "+" s
|
||||
#else
|
||||
#define OPTIONS(s) s
|
||||
#endif
|
||||
|
||||
extern uint32_t swPresent;
|
||||
extern char *swValue[];
|
||||
|
||||
#define SWISSET(c) ((swPresent & (1 << (c - 'a'))) != 0)
|
||||
#define SWSET(c) swPresent |= (1 << (c - 'a'))
|
||||
#define SWGETVAL(c) (swValue[c - 'a'])
|
||||
#define SWSETVAL(c, v) swValue[c - 'a'] = v
|
||||
|
||||
#ifdef DEBUG
|
||||
extern FILE *DEBUGout;
|
||||
#define ERROR(...) { \
|
||||
fprintf(stderr, __VA_ARGS__); \
|
||||
if ((DEBUGout != NULL) && (DEBUGout != stdout)) \
|
||||
fprintf(DEBUGout, __VA_ARGS__); \
|
||||
}
|
||||
#else
|
||||
#define ERROR(...) fprintf(stderr, __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
struct mountedFS;
|
||||
|
||||
/*
|
||||
* File system definition
|
||||
*/
|
||||
struct FSdef {
|
||||
struct FSdef *next; /* Pointer to next file system */
|
||||
char *fstype; /* File system type name */
|
||||
char *descr; /* File system description */
|
||||
uint16_t flags; /* Flags */
|
||||
size_t blocksz; /* Default block size */
|
||||
int (*mount)(struct mountedFS *);
|
||||
void (*umount)(struct mountedFS *);
|
||||
size_t (*size)(void);
|
||||
int (*newfs)(struct mountedFS *, size_t);
|
||||
void (*set)(struct mountedFS *, uint8_t, uint8_t);
|
||||
void (*info)(struct mountedFS *, uint8_t, uint8_t);
|
||||
void (*dir)(struct mountedFS *, uint8_t, char *);
|
||||
void *(*openFileR)(struct mountedFS *, uint8_t, char *);
|
||||
void *(*openFileW)(struct mountedFS *, uint8_t, char *, off_t);
|
||||
off_t (*fileSize)(void *);
|
||||
void (*closeFile)(void *);
|
||||
size_t (*readFile)(void *, void *, size_t);
|
||||
size_t (*writeFile)(void *, void *, size_t);
|
||||
void (*deleteFile)(void *, char *);
|
||||
/*
|
||||
* The following functions are only supported by magtape file systems.
|
||||
*/
|
||||
void (*rewind)(struct mountedFS *);
|
||||
void (*eom)(struct mountedFS *);
|
||||
void (*skipforw)(struct mountedFS *, unsigned long);
|
||||
void (*skiprev)(struct mountedFS *, unsigned long);
|
||||
};
|
||||
#define FS_UNITVALID 0x0001 /* Unit # valid in device name */
|
||||
#define FS_TAPE 0x0002 /* File system for magtapes */
|
||||
#define FS_EMPTYFILE 0x0004 /* Empty file is OK */
|
||||
#define FS_1OPENFILE 0x0008 /* Only support a single open file */
|
||||
|
||||
/*
|
||||
* Mounted file system descriptor
|
||||
*/
|
||||
struct mountedFS {
|
||||
struct mountedFS *next; /* Pointer to next mounted file sys */
|
||||
char name[MAX_DEVLEN + 1];
|
||||
struct FSdef *filesys; /* File system */
|
||||
size_t blocksz; /* Active block size */
|
||||
uint16_t flags;
|
||||
#define FS_READONLY 0x0001 /* Mounted read-only */
|
||||
#define FS_DEBUG 0x0002 /* Debug output */
|
||||
/* Bits after 0x0080 reserved for */
|
||||
/* file system use */
|
||||
FILE *container; /* Container file access */
|
||||
union {
|
||||
struct DOS11data _dos11;
|
||||
struct RT11data _rt11;
|
||||
struct DOSMTdata _dosmt;
|
||||
} FSdata;
|
||||
#define dos11data FSdata._dos11
|
||||
#define rt11data FSdata._rt11
|
||||
#define dosmtdata FSdata._dosmt
|
||||
};
|
||||
|
||||
extern int FSioReadBlock(struct mountedFS *, unsigned int, void *);
|
||||
extern int FSioWriteBlock(struct mountedFS *, unsigned int, void *);
|
||||
|
||||
#endif
|
||||
319
converters/fsio/fsio.txt
Normal file
319
converters/fsio/fsio.txt
Normal file
@ -0,0 +1,319 @@
|
||||
fsio is a utility for manipulating files within file system container files
|
||||
supported by by various emulators such as SIMH. fsio is designed for Unix and
|
||||
Unix-like operating systems.
|
||||
|
||||
fsio is executed by the command:
|
||||
|
||||
fsio [-qv] [cmdfile]
|
||||
|
||||
If cmdfile is present, fsio will read commands from the command file and
|
||||
echoing each command to stdout if -v . present. If the -q switch is present,
|
||||
no unsolicited output will be generated by fsio. If the command file is not
|
||||
present fsio will prompt for input:
|
||||
|
||||
fsio>
|
||||
|
||||
Commands to fsio have the following general syntax:
|
||||
|
||||
verb [switches] args...
|
||||
|
||||
The following verbs are supported:
|
||||
|
||||
mount - makes a container file available to fsio and specifies the file
|
||||
system it contains.
|
||||
|
||||
umount - removes knowledge of a container file from fsio
|
||||
|
||||
newfs - create a new container with an empty file system
|
||||
|
||||
set - set file system parameters
|
||||
|
||||
info - display information about the file system
|
||||
|
||||
dir - list a directory
|
||||
|
||||
dump - Dump the contents of a file in a human readable format
|
||||
|
||||
copy - copies a single file
|
||||
|
||||
type - types the contents of a file on the terminal
|
||||
|
||||
delete - deletes a file
|
||||
|
||||
status - displays the currently mounted file systems
|
||||
|
||||
do - execute commands from a file
|
||||
|
||||
help - display help on using fsio
|
||||
|
||||
exit - terminate fsio
|
||||
|
||||
The following commands are only accepted by file systems which are on magtape
|
||||
devices:
|
||||
|
||||
rewind - position the tape to the start of the data stream
|
||||
|
||||
eom - position the tape to the end of the data stream
|
||||
|
||||
skipf - position the tape by skipping forward over a number of files
|
||||
|
||||
skipr - position the tape by skipping backwards over a number of files
|
||||
|
||||
fsio will accept shorter versions of each verb as long as they are unique
|
||||
within the command set, so c, co and cop are all synonyms for copy.
|
||||
|
||||
The generic form of the "dev" argument is "DDnn:" where the ":" is optional
|
||||
in some commands. DD is a sequence of upper and lower case letters and nn is
|
||||
an octal number in the range 0 - 377. The length of "DDnn" must not exceed 16
|
||||
characters. In most cases the number field should not be present and will be
|
||||
flagged as an error if it is. Some container file formats, e.g. RT-11, allow
|
||||
multiple file systems within a single container and the number is used to
|
||||
specify which file system to use. For these types of containers the following
|
||||
rules apply:
|
||||
|
||||
- For "mount" and "umount" commands always use "DD:"
|
||||
|
||||
- For file access commands (e.g. "dir", "type" etc) use "DDnn:" ("DD:"
|
||||
is treated the same as "DD0:")
|
||||
|
||||
- The "info" command use the presence/absence of the number to control
|
||||
what information is display. If "DD:" is used, it will display
|
||||
information abount all file systems within the container. If "DDnn:"
|
||||
is used, it will only display information about the specific file
|
||||
system.
|
||||
|
||||
|
||||
Full command syntax:
|
||||
|
||||
1. mount
|
||||
|
||||
mount [-dr] dev[:] container type
|
||||
|
||||
Make the specified container file available to fsio for I/O.
|
||||
|
||||
-d Generate debug output if fsio is built with the DEBUG symbol
|
||||
defined
|
||||
-r If present, the file system is only available for read access
|
||||
|
||||
dev[:] User supplied name to be used for accessing files within the
|
||||
container file. Files within the container are named by using
|
||||
the syntax dev:filespec where filespec uses the native syntax
|
||||
of the container file system. Files within the host file
|
||||
system can be named directly without any prefix. If such a
|
||||
file includes ':' in its filename, the reserved prefix local:
|
||||
may be used to provide access. If you want to disallow default
|
||||
access to the local filesystem, creating an environment
|
||||
variable with the name "FSioForceLocal" (the value does not
|
||||
matter) will require use of the "local:" prefix.
|
||||
|
||||
container The name of the file containing the file system
|
||||
|
||||
type The type of the file system in the container
|
||||
|
||||
2. umount
|
||||
|
||||
umount dev[:]
|
||||
|
||||
Removes all knowledge of the container file from fsio
|
||||
|
||||
dev[:] The name of a previously mounted file system
|
||||
|
||||
3. newfs
|
||||
|
||||
newfs [-t type] container type
|
||||
|
||||
Create a new container file with an empty file system. The container
|
||||
will be a fixed size (depending on file system type) and may not exist
|
||||
prior to issuing this command. This command does not support all features
|
||||
of container files and will build a fixed size container known to work
|
||||
on the target O/S:
|
||||
|
||||
dos11 RK05 image (2.5MB, 4800 blocks)
|
||||
rt11 MSCP image (32MB, 65535 blocks)
|
||||
dosmt An empty file suitable for use with any magtape controller
|
||||
|
||||
-t type Use a different size for the container file. The size used
|
||||
will be file system dependent.
|
||||
|
||||
For rt11, the following disk types are valid:
|
||||
|
||||
rl02 RL02 image (10MB, 20480 blocks)
|
||||
rx20 RX20 image (512KB, 1024 blocks)
|
||||
|
||||
container The name of the file to create
|
||||
|
||||
type The type of the file system to create in the container
|
||||
|
||||
4. set
|
||||
|
||||
set dev: args ...
|
||||
|
||||
Set parameters on a mounted file system. The arguments are file system
|
||||
dependent.
|
||||
|
||||
dev: The name of a previously mounted file system
|
||||
|
||||
5. info
|
||||
|
||||
info dev:
|
||||
|
||||
Display internal information about the file system within the container
|
||||
file
|
||||
|
||||
dev: The name of a previously mounted file system
|
||||
|
||||
6. dir
|
||||
|
||||
dir [-fn] dev:dirspec
|
||||
|
||||
List the contents of a specific directory.
|
||||
|
||||
-f If present, display full directory information.
|
||||
|
||||
-n If present, don't rewind the magtape before listing
|
||||
|
||||
dev: The name of a previosly mounted file system
|
||||
dirspec Specification of the directory to list using the dev: syntax.
|
||||
|
||||
7. dump
|
||||
|
||||
dump [-bcdnwx] dev:src
|
||||
|
||||
Dump the contents of a specified file in some human readable format (e.g
|
||||
hex, octal etc). If no switches are present, the output will be in octal
|
||||
word format. If multiple size switches are set, the first in alphabetical
|
||||
order will take precedence.
|
||||
|
||||
-b Output byte at a time
|
||||
-d Output double word (4 bytes) at a type
|
||||
-c Output ASCII characters
|
||||
-w Output word (2 bytes) at a time
|
||||
|
||||
-x Output the data in hex
|
||||
|
||||
-n Don't rewind the magtape before looking for the input file
|
||||
|
||||
dev: The name of a previosly mounted file system
|
||||
src The name of the source file (e.g. dp:input.dat)
|
||||
|
||||
8. copy
|
||||
|
||||
copy [-anpc blocks] dev1:src dev2:dest
|
||||
|
||||
Copy a file. The copy may be between file systems or within a single
|
||||
filesystem including the host filesystem.
|
||||
|
||||
-a Copy in ASCII mode. This performs any necessary translation
|
||||
of end-of-line characters.
|
||||
|
||||
-n Don't rewind the magtape before looking for the input file
|
||||
|
||||
-p Pad the file with NULLs. This is target file system
|
||||
dependent.
|
||||
|
||||
-c blocks If the file system for the destination file supports
|
||||
contiguous files, "blocks" is the number of file system
|
||||
contiguous files to be allocated before starting to write
|
||||
the file. This function depends on the value of "blocks":
|
||||
|
||||
0 - Use the size of the source file for the allocation,
|
||||
if that is 0 (e.g. input from a keyboard) use 1.
|
||||
|
||||
!= 0 - Use the larger of "blocks" and the size of the
|
||||
source file.
|
||||
|
||||
dev1: The name of a previosly mounted file system
|
||||
src The name of the source file (e.g. dk:source.file)
|
||||
|
||||
dev2: The name of a previously mounted file system
|
||||
dest The name of the desination file (e.g. dm:dest.file)
|
||||
|
||||
Note that wildcard naming is not supported and the source and destination
|
||||
file names must be fully specified.
|
||||
|
||||
9. type
|
||||
|
||||
type [-n] dev:src
|
||||
|
||||
Copies the specified file to the terminal. This is equivalent to
|
||||
|
||||
copy -a dev:src /dev/tty
|
||||
|
||||
-n Don't rewind the magtape before looking for the input file
|
||||
|
||||
dev: The name of a previously mounted file system
|
||||
src The name of the source file (e.g. dp:input.txt)
|
||||
|
||||
10. delete
|
||||
|
||||
delete dev:file
|
||||
|
||||
Deletes the specified file from the file system.
|
||||
|
||||
dev: The name of a previously mounted file system
|
||||
file The name of the file to be deleted
|
||||
|
||||
11. status
|
||||
|
||||
status
|
||||
|
||||
Displays the currently mounted file systems.
|
||||
|
||||
12. do
|
||||
|
||||
do [-q] cmdFile
|
||||
|
||||
Executes commands from the specified file
|
||||
|
||||
-q By default, command lines are echoed. Use -q to not echo.
|
||||
|
||||
13. help
|
||||
|
||||
help
|
||||
|
||||
Display help text on the terminal.
|
||||
|
||||
14. exit
|
||||
|
||||
exit
|
||||
|
||||
Terminates the fsio application.
|
||||
|
||||
15. rewind
|
||||
|
||||
rewind dev:
|
||||
|
||||
Positions a magtape device to the start of the tape.
|
||||
|
||||
dev: The name of a previously mounted file system
|
||||
|
||||
16. eom
|
||||
|
||||
eom dev:
|
||||
|
||||
Positions a magtape device past the end of the last file already on the
|
||||
tape. A subsequent copy to the device will append a new file to the tape.
|
||||
|
||||
dev: The name of a previously mounted file system
|
||||
|
||||
17. skipf
|
||||
|
||||
skipf dev: n
|
||||
|
||||
Changes the current position of the magtape device by skipping forwards
|
||||
over a number of files. If end of tape is reached before the file count is
|
||||
complete, the skip operation will terminate early.
|
||||
|
||||
dev: The name of a previously mounted file system
|
||||
n Number of files to skip (must be > 0)
|
||||
|
||||
18. skipr
|
||||
|
||||
skipr dev: n
|
||||
|
||||
Changes the current position of the magtape device by skipping backwards
|
||||
over a number of files. If beginning of tape is reached before the file
|
||||
count is complete, the skip operation will terminate early.
|
||||
|
||||
dev: The name of a previously mounted file system
|
||||
n Number of files to skip (must be > 0)
|
||||
291
converters/fsio/fsioSimh.txt
Normal file
291
converters/fsio/fsioSimh.txt
Normal file
@ -0,0 +1,291 @@
|
||||
How to use fsio to transfer files in/out of SIMH emulators
|
||||
----------------------------------------------------------
|
||||
|
||||
The examples below assume a basic knowlegde of fsio (see the man pages - fsio.1
|
||||
fsio-dos11.1 and fsio-rt11.1). The following examples assume that we want to
|
||||
move an ASCII formatted file "file.txt" into the target operating system. If
|
||||
fsio understands the target file system (DOS-11 and RT-11 right now), we can
|
||||
copy the file directly into the SIMH container file used for booting the
|
||||
operating system. For other target file systems we need to transfer into a
|
||||
file system that the target operating system understands, even if it is not
|
||||
the native file system for that operation system. In the DEC world, this is
|
||||
typically RT-11.
|
||||
|
||||
Note: all of these examples assume that we are running on a Linux or Unix-like
|
||||
operating system (in my case Raspbian on a Raspberry Pi).
|
||||
|
||||
WARNING: fsio is alpha-level code. Make sure you make a back-up copy of any
|
||||
important file system before mounting it read/write.
|
||||
|
||||
|
||||
Native File System Support
|
||||
--------------------------
|
||||
|
||||
DOS-11
|
||||
------
|
||||
|
||||
For DOS-11, fsio understands the native disk format so we can transfer
|
||||
directly into the bootable SIMH disk ("system.dsk" in the examples).
|
||||
|
||||
pi@host:~ $ fsio
|
||||
fsio> mount dk: system.dsk dos11
|
||||
dk: successfully mounted
|
||||
Total blocks: 4800, Free blocks: 3591, Interleave: 1
|
||||
fsio> copy -a file.txt dk:file.txt
|
||||
fsio> quit
|
||||
pi@host:~ $
|
||||
|
||||
This will copy file.txt into the default UFD ([1,1]) on the target file system.
|
||||
The copy will be in ASCII mode meaning that line endings will be translated
|
||||
into the character pair <cr><lf> which DOS/BATCH-11 requires. If you wish to
|
||||
transfer the file into another (existing) UFD (e.g. [200,200]) you can use
|
||||
either of the following 2 options:
|
||||
|
||||
fsio> copy -a file.txt dk:file.txt[200,200]
|
||||
|
||||
or
|
||||
fsio> set dk: uic [200,200]
|
||||
fsio> copy -a file.txt dk:file.txt
|
||||
|
||||
If the destination UFD does not already exist on the target file system use
|
||||
the following to create the UFD:
|
||||
|
||||
fsio> set dk: ufd [200,200]
|
||||
fsio> copy -a file.txt dk:file.txt
|
||||
|
||||
RT-11
|
||||
-----
|
||||
|
||||
For RT-11, fsio understands the native disk format so we can transfer
|
||||
directly into the bootable SIMH disk ("rt11sys.dsk" in the examples). Note
|
||||
that RT-11 disk images can hold multiple partitions, each having a maximum
|
||||
size of 32MB. Partitions are named by appending an octal number to the device
|
||||
name - xx0: will be the first partition, xx1: the second etc. fsio will only
|
||||
allow access to partitions which have been initialized with an RT-11 file
|
||||
system. The example below shows a disk with 3 partitions but only the first
|
||||
and last have been initialized.
|
||||
|
||||
pi@host:~ $ fsio
|
||||
fsio> mount dk: rt11sys.dsk rt11
|
||||
dk: successfully mounted (2 partitions)
|
||||
|
||||
dk0:
|
||||
Total blocks: 65536, Free blocks: 24279
|
||||
Directory segments: 31 (Highest 4)
|
||||
Extra bytes/directory entry: 0
|
||||
dk2:
|
||||
Total blocks: 65536, Free blocks: 65422
|
||||
Directory segments: 31 (Highest 1)
|
||||
Extra bytes/directory entry: 0
|
||||
fsio> copy -a file.txt dk:file.txt
|
||||
fsio> quit
|
||||
pi@host:~ $
|
||||
|
||||
This will copy file.txt into the target file system. The copy will be in
|
||||
ASCII mode meaning that line endings will be translated into the character
|
||||
pair <cr><lf> which RT-11 requires. In addition, unless the file ends
|
||||
exactly on a block (512 bytes) boundary, a ^Z (octal 32) will be appended
|
||||
to the file indicating end-of-file.
|
||||
|
||||
|
||||
Foreign File System Support
|
||||
---------------------------
|
||||
|
||||
For other target operating systems we will use an RT-11 format RL02 disk as an
|
||||
intermediary for performing the transfer:
|
||||
|
||||
pi@host:~ $ fsio
|
||||
fsio> newfs -a xfer.dsk rt11
|
||||
fsio> mount dk: xfer.dsk rt11
|
||||
fsio> copy -a file.txt dk:file.txt
|
||||
fsio> quit
|
||||
pi@host:~ $
|
||||
|
||||
This will create a maximum sized, single partition RT-11 file system in a
|
||||
container file called "xfer.dsk" which may be copied to the target system
|
||||
running SIMH.
|
||||
|
||||
Once on the target system, the commands to copy the file into the emulated
|
||||
operating system will depend on that operating system and, possible, its age.
|
||||
|
||||
RSX-11M/RSX-11M+
|
||||
----------------
|
||||
|
||||
Use the FLX utility to copy the file over to the Files-11 file system:
|
||||
|
||||
>set /uic=[1,2]
|
||||
>^E
|
||||
Simulation stopped, PC: 017460 (BR 17426)
|
||||
sim> att rq2 xfer.dsk
|
||||
sim> c
|
||||
|
||||
>all du2:
|
||||
>mou du2:/for
|
||||
>ins $flx
|
||||
>flx [200,200]/fa=du2:file.txt/rt
|
||||
>pip [200,200]file.txt/fu
|
||||
|
||||
|
||||
Directory DU0:[200,200]
|
||||
2019-01-10 18:10
|
||||
|
||||
FILE.TXT;1 (6400,15) 1./1. 2019-01-10 18:09
|
||||
[1,2] [RWED,RWED,RWED,R]
|
||||
|
||||
Total of 1./1. blocks in 1. file
|
||||
|
||||
>dmo du2:
|
||||
18:10:28 *** DU2: -- Dismount complete
|
||||
DMO -- TT0: dismounted from DU2: *** Final dismount initiated ***
|
||||
>dea du2:
|
||||
>^E
|
||||
Simulation stopped, PC: 017460 (BR 17426)
|
||||
sim> det rq2
|
||||
sim> c
|
||||
|
||||
>
|
||||
|
||||
Note that RSX FLX cannot handle formatted ASCII input files with an embedded
|
||||
^Z character indicating end-of-file. Use the "-p" switch during the copy to
|
||||
pad the file with NULLs.
|
||||
|
||||
IAS
|
||||
---
|
||||
|
||||
The following example assumes that you are logged into a non-console
|
||||
terminal. You will still need to break in on the cosole with ^E and attach
|
||||
the RT-11 transfer disk as in all the other examples.
|
||||
|
||||
PDS> ALLOC DL0:
|
||||
PDS> MOU/FOR DL0:
|
||||
MOUNT-**Volume Information**
|
||||
Device =DL0
|
||||
Class =Foreign
|
||||
UIC =[201,201]
|
||||
Access =[RWED,RWED,RWED,RWED]
|
||||
Charac =[FOR,ATCH,DCF]
|
||||
PDS> DIR DL0:/RT
|
||||
|
||||
|
||||
DIRECTORY DL0:
|
||||
31-JAN-99
|
||||
|
||||
FILE .TXT 1. 12-87
|
||||
< UNUSED > 20411.
|
||||
|
||||
20411. FREE BLOCKS
|
||||
|
||||
TOTAL OF 1. BLOCKS IN 1. FILES
|
||||
|
||||
PDS> COPY DL:FILE.TXT/RT *.*
|
||||
PDS> DIR
|
||||
|
||||
|
||||
Directory DU0:[201,201]
|
||||
31-JAN-99 15:56
|
||||
|
||||
FILE.TXT;1 1. 31-JAN-99 15:56
|
||||
|
||||
Total of 1./1. blocks in 1. file
|
||||
|
||||
PDS> DISM DL0:
|
||||
DMO -- DL00: ** DISMOUNT COMPLETE **
|
||||
|
||||
Note that in order to use the RL02 drive from timesharing, the following
|
||||
changes will need to be made to the IAS startup scripts of the PiDP-11
|
||||
distribution:
|
||||
|
||||
1. [1,1]STARTUP.CMD
|
||||
|
||||
Add the following lines at the start of the file:
|
||||
|
||||
INS [11,1]DL
|
||||
LOA DL
|
||||
|
||||
2. [1,1]IASSTART.CMD
|
||||
|
||||
Add the following lines after the one containing "DU0/S":
|
||||
|
||||
DL0
|
||||
DL1
|
||||
|
||||
After making these changes, reboot the system and users will be able to access
|
||||
the 2 RL02 drives.
|
||||
|
||||
|
||||
RSTS/E
|
||||
------
|
||||
|
||||
For this example I have used the "-a" on the fsio "newfs" command to create an
|
||||
empty RL02 disk image. Use the "-p" switch on the fsio "copy" command to pad
|
||||
the file with NULLs, otherwise the ^Z will be copied into the RSTS/E file. Use
|
||||
the FIT utility to copy the file over to the RSTS/E file system:
|
||||
|
||||
$ ^E
|
||||
Simulation stopped, PC: 065640 (BR 65630)
|
||||
sim> att rl0 xfer.dsk
|
||||
sim> c
|
||||
|
||||
$ run auxlib$:fit
|
||||
FIT V10.1-A RSTS V10.1-L RSTS/E V10.1
|
||||
FIT>sy:=dl0:file.txt/rt11
|
||||
FIT>^Z
|
||||
$ dir file.txt/fu
|
||||
|
||||
Name .Typ Size Prot Access Date Time Clu RTS Pos Op/rr SY:[1,2]
|
||||
FILE .TXT 1 < 60> 12-Jan-19 12-Jan-87 04:23 PM 8 RT11 214 0/0
|
||||
|
||||
Total of 1 block in 1 file in SY:[1,2]
|
||||
|
||||
$ ^E
|
||||
Simulation stopped, PC: 065640 (BR 65630)
|
||||
sim> det rl0
|
||||
sim> c
|
||||
|
||||
$
|
||||
|
||||
VMS
|
||||
---
|
||||
|
||||
Use the exchange utility to copy the file over to the VMS file system:
|
||||
|
||||
$^E
|
||||
Simulation stopped, PC: 80B90B8D (BBC #3,26C(R3),80B90BE1)
|
||||
sim> att rq1 xfer.dsk
|
||||
sim> c
|
||||
|
||||
$ mou/for dua1:
|
||||
%MOUNT-I-MOUNTED, mounted on _ROUTER$DUA1:
|
||||
$ exchange copy dua1:file.txt/volume=rt11/record=stream file.txt
|
||||
%EXCHANGE-S-MOUNTED, the RT-11 volume _ROUTER$DUA1: has been mounted
|
||||
$ dism dua1:
|
||||
$^E
|
||||
Simulation stopped, PC: 80B90936 (ASHL #1,R3,R0)
|
||||
sim> det rq1
|
||||
sim> c
|
||||
|
||||
$ dir file.txt
|
||||
|
||||
Directory SYS$SYSROOT:[SYSMGR]
|
||||
|
||||
FILE.TXT;1
|
||||
|
||||
Total of 1 file.
|
||||
$
|
||||
|
||||
This can be especially useful for getting the Hobbyist licences into VMS
|
||||
before you have any network running.
|
||||
|
||||
TOPS-10
|
||||
-------
|
||||
|
||||
Use the RTFLX utility to copy the file over to the TOPS-10 file system. When
|
||||
creating the SIMH file using the "newfs" command use the "-t rx20" switch to
|
||||
create a floppy image. The RX20 is a double density floppy and is only
|
||||
available on KS10 systems.
|
||||
|
||||
There is a help file on Tops-10 for RTFLX but no other documentation. The
|
||||
default TOPS-10 monitor does not include support for the RX20 so a new
|
||||
system generation will be required.
|
||||
|
||||
I do not currently have a functioning TOPS-10 system to test this on.
|
||||
377
converters/fsio/local.c
Normal file
377
converters/fsio/local.c
Normal file
@ -0,0 +1,377 @@
|
||||
/*
|
||||
* Copyright (C) 2018 John Forecast. All Rights Reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY JOHN FORECAST "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Support routines for local file access under fsio.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "fsio.h"
|
||||
|
||||
/*++
|
||||
* l o c a l I n f o
|
||||
*
|
||||
* Display information about the local file system. This is not supported
|
||||
* by the "local" device.
|
||||
*
|
||||
* Inputs:
|
||||
*
|
||||
* mount - pointer to the mounted file system descriptor
|
||||
* unit - device unit number (unused)
|
||||
* present - device unit number present (unused)
|
||||
*
|
||||
* Outputs:
|
||||
*
|
||||
* None
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* None
|
||||
*
|
||||
--*/
|
||||
static void localInfo(
|
||||
struct mountedFS *UNUSED(mount),
|
||||
uint8_t UNUSED(unit),
|
||||
uint8_t UNUSED(present)
|
||||
)
|
||||
{
|
||||
fprintf(stderr, "info: The \"local:\" device does not support this command\n");
|
||||
}
|
||||
|
||||
/*++
|
||||
* l o c a l D i r
|
||||
*
|
||||
* Produce a full or brief directory listing.
|
||||
*
|
||||
* Inputs:
|
||||
*
|
||||
* mount - pointer to the mounted file system descriptor
|
||||
* unit - device unit number
|
||||
* fname - pointer to filename string
|
||||
*
|
||||
* Outputs:
|
||||
*
|
||||
* None
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* None
|
||||
*
|
||||
--*/
|
||||
static void localDir(
|
||||
struct mountedFS *UNUSED(mount),
|
||||
uint8_t UNUSED(unit),
|
||||
char *fname
|
||||
)
|
||||
{
|
||||
char cmd[64];
|
||||
|
||||
sprintf(cmd, "/bin/ls %s%s\n",
|
||||
SWISSET('f') ? "-l " : "", fname);
|
||||
system(cmd);
|
||||
}
|
||||
|
||||
/*++
|
||||
* l o c a l O p e n F i l e R
|
||||
*
|
||||
* Open a local file for reading.
|
||||
*
|
||||
* Inputs:
|
||||
*
|
||||
* mount - pointer to the mounted file system descriptor
|
||||
* unit - device unit number
|
||||
* fname - pointer to filename string
|
||||
*
|
||||
* Outputs:
|
||||
*
|
||||
* None
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* Pointer to open file descriptor, NULL if open fails
|
||||
*
|
||||
--*/
|
||||
static void *localOpenFileR(
|
||||
struct mountedFS *UNUSED(mount),
|
||||
uint8_t UNUSED(unit),
|
||||
char *fname
|
||||
)
|
||||
{
|
||||
return fopen(fname, "r");
|
||||
}
|
||||
|
||||
/*++
|
||||
* l o c a l O p e n F i l e W
|
||||
*
|
||||
* Open a local file for writing.
|
||||
*
|
||||
* Inputs:
|
||||
*
|
||||
* mount - pointer to the mounted file system descriptor
|
||||
* unit - device unit number
|
||||
* fname - pointer to filename string
|
||||
* size - estimated file size (in bytes)
|
||||
*
|
||||
* Outputs:
|
||||
*
|
||||
* None
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* Pointer to open file descriptor, NULL if open fails
|
||||
*
|
||||
--*/
|
||||
static void *localOpenFileW(
|
||||
struct mountedFS *UNUSED(mount),
|
||||
uint8_t UNUSED(unit),
|
||||
char *fname,
|
||||
off_t UNUSED(size)
|
||||
)
|
||||
{
|
||||
return fopen(fname, "w");
|
||||
}
|
||||
|
||||
/*++
|
||||
* l o c a l F i l e S i z e
|
||||
*
|
||||
* Return the size of a currently open file. If the file is open in ASCII
|
||||
* mode we do not know how many lines are present in the file and so cannot
|
||||
* calculate how much additional space will be needed for a possible <LF>
|
||||
* to <CRLF> translation. In this case we return 0.
|
||||
*
|
||||
* Inputs:
|
||||
*
|
||||
* filep - pointer to open file descriptor
|
||||
*
|
||||
* Outputs:
|
||||
*
|
||||
* None
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* Current size of the file, 0 on error
|
||||
*
|
||||
--*/
|
||||
static off_t localFileSize(
|
||||
void *filep
|
||||
)
|
||||
{
|
||||
FILE *file = filep;
|
||||
struct stat stat;
|
||||
|
||||
if (!SWISSET('a'))
|
||||
if (fstat(fileno(file), &stat) == 0)
|
||||
return stat.st_size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*++
|
||||
* l o c a l D e l e t e F i l e
|
||||
*
|
||||
* Delete a local file.
|
||||
*
|
||||
* Inputs:
|
||||
*
|
||||
* file - pointer to open file descriptor
|
||||
* fname - pointer to filename string
|
||||
*
|
||||
* Outputs:
|
||||
*
|
||||
* None
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* None
|
||||
*
|
||||
--*/
|
||||
static void localDeleteFile(
|
||||
void *file,
|
||||
char *fname
|
||||
)
|
||||
{
|
||||
fclose(file);
|
||||
|
||||
if (unlink(fname) != 0)
|
||||
fprintf(stderr, "delete: failed to delete \"%s\"\n", fname);
|
||||
}
|
||||
|
||||
/*++
|
||||
* l o c a l C l o s e F i l e
|
||||
*
|
||||
* Close an open local file.
|
||||
*
|
||||
* Inputs:
|
||||
*
|
||||
* file - pointer to open file descriptor
|
||||
*
|
||||
* Outputs:
|
||||
*
|
||||
* None
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* None
|
||||
*
|
||||
--*/
|
||||
static void localCloseFile(
|
||||
void *file
|
||||
)
|
||||
{
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
/*++
|
||||
* l o c a l R e a d F i l e
|
||||
*
|
||||
* Read from a local file into a supplied buffer. If ASCII mode is active,
|
||||
* each read will return at most 1 line of data and any terminating <LF> will
|
||||
* be translated into <CRLF>.
|
||||
*
|
||||
* Inputs:
|
||||
*
|
||||
* file - pointer to open file descriptor
|
||||
* buf - pointer to buffer
|
||||
* buflen - length of the supplied buffer
|
||||
*
|
||||
* Outputs:
|
||||
*
|
||||
* None
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* # of bytes of data read, 0 means EOF or error
|
||||
*
|
||||
--*/
|
||||
static size_t localReadFile(
|
||||
void *file,
|
||||
void *buf,
|
||||
size_t buflen
|
||||
)
|
||||
{
|
||||
if (SWISSET('a')) {
|
||||
char *bufr = buf;
|
||||
int readlen;
|
||||
|
||||
if (fgets(bufr, buflen - 1, file) == NULL)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Translate terminating \n into \r\n unless it is already there
|
||||
*/
|
||||
if ((readlen = strlen(bufr)) != 0) {
|
||||
if (bufr[readlen - 1] == '\n') {
|
||||
if ((readlen == 1) || (bufr[readlen - 2] != '\r'))
|
||||
strcpy(&bufr[readlen - 1], "\r\n");
|
||||
}
|
||||
}
|
||||
return strlen(bufr);
|
||||
}
|
||||
return fread(buf, sizeof(char), buflen, file);
|
||||
}
|
||||
|
||||
/*++
|
||||
* l o c a l W r i t e F i l e
|
||||
*
|
||||
* Write to a local file from a supplied buffer. If ASCII mode is active,
|
||||
* if the buffer is terminated with <CRLF> translate it into <LF>.
|
||||
*
|
||||
* Inputs:
|
||||
*
|
||||
* file - pointer to open file descriptor
|
||||
* buf - pointer to buffer
|
||||
* buflen - length of the supplied buffer
|
||||
*
|
||||
* Outputs:
|
||||
*
|
||||
* None
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* # of bytes of data written, 0 means error
|
||||
*
|
||||
--*/
|
||||
static size_t localWriteFile(
|
||||
void *file,
|
||||
void *buf,
|
||||
size_t buflen
|
||||
)
|
||||
{
|
||||
if (SWISSET('a')) {
|
||||
char *bufw = buf;
|
||||
|
||||
if (buflen >= 2)
|
||||
if ((bufw[buflen - 2] == '\r') && (bufw[buflen - 1] == '\n')) {
|
||||
bufw[buflen - 2] = '\n';
|
||||
buflen--;
|
||||
}
|
||||
}
|
||||
return fwrite(buf, sizeof(char), buflen, file);
|
||||
}
|
||||
|
||||
/*++
|
||||
* l o c a l F S
|
||||
*
|
||||
* Descriptor for accessing local files. Note that none of command routines
|
||||
* are present since this device never appears to be mounted.
|
||||
--*/
|
||||
struct FSdef localFS = {
|
||||
NULL,
|
||||
"local",
|
||||
"local Local file access\n",
|
||||
0,
|
||||
0,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
localInfo,
|
||||
localDir,
|
||||
localOpenFileR,
|
||||
localOpenFileW,
|
||||
localFileSize,
|
||||
localCloseFile,
|
||||
localReadFile,
|
||||
localWriteFile,
|
||||
localDeleteFile,
|
||||
NULL, /* No tape support functions */
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
/*
|
||||
* Statically allocated mounted file system for local file access
|
||||
*/
|
||||
struct mountedFS localMount;
|
||||
2306
converters/fsio/rt11.c
Normal file
2306
converters/fsio/rt11.c
Normal file
File diff suppressed because it is too large
Load Diff
290
converters/fsio/rt11.h
Normal file
290
converters/fsio/rt11.h
Normal file
@ -0,0 +1,290 @@
|
||||
/*
|
||||
* Copyright (C) 2018 John Forecast. All Rights Reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY JOHN FORECAST "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef __RT11_H__
|
||||
#define __RT11_H__
|
||||
|
||||
/*
|
||||
* General disk layout:
|
||||
*
|
||||
* Block
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* 0 | Reserved |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* 1 | Home Block (Reserved) |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* 2 | Reserved |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* 3 | Reserved |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* 4 | Reserved |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* 5 | Reserved |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* 6 | Directory Segment 1 |
|
||||
* 7 | |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* 10 | Directory Segment 2 |
|
||||
* 11 | |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* | ... |
|
||||
* | ... |
|
||||
* | ... |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* x | Directory Segment n |
|
||||
* x+1 | |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* Files | ... |
|
||||
* | ... |
|
||||
* | ... |
|
||||
* | ... |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* End of Volume
|
||||
*
|
||||
* Home Block:
|
||||
*
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* 0000 | Bad block replacement table |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* 0202 | Unused |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* 0204 | INITIALIZE/RESTORE data area |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* 0252 | BUP Information area |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* 0274 | Unused |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* 0700 | Reserved for Digital - 000000 |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* 0702 | Reserved for Digital - 000000 |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* 0704 | Unused |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* 0722 | Pack cluster size - 000001 |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* 0724 | Block # of first directory segment - 000006 |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* 0726 | System version - Radix-50 "V3A"? |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* 0730 | Volume identification - "RT11A " |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* 0744 | Owner name - " " |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* 0760 | System identification - "DECRT11A " |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* 0776 | Checksum |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
*
|
||||
* Directory Segment Header:
|
||||
*
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* | Total # of directory segments (1 - 31) |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* | Next logical directory segment # |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* | Highest directory segment in use |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* | Extra bytes per directory entry |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* | Block # for start of this segment |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
*
|
||||
* Directory Entry:
|
||||
*
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* | Status Word |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* | Radix-50 File Name (chars 1 - 3) |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* | Radix-50 File Name (chars 4 - 6) |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* | Radix-50 File Type (1 - 3 chars) |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* | Job # | Channel # |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* | Creation Date |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* | Optional Extra Words |
|
||||
* | ... |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
*
|
||||
* Status Word:
|
||||
*
|
||||
* 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* | | | | | | | | | | | | | | | | |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* | | | | | | |
|
||||
* | | | | | | - Prefix block indicator
|
||||
* | | | | | - Tentative file
|
||||
* | | | | - Empty area
|
||||
* | | | - Permanent file
|
||||
* | | - End of segment marker
|
||||
* | - Protected from .WRITE requests
|
||||
* - Protected permanent file
|
||||
*
|
||||
* Date Word:
|
||||
*
|
||||
* 15 14 13 10 9 5 4 0
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* | | | | |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* | | | | | | | |
|
||||
* +---+ +-----------+ +---------------+ +---------------+
|
||||
* | | | |
|
||||
* | | | Year - 1972
|
||||
* | | | - 32 x Age
|
||||
* | | - Day (1 - 31)
|
||||
* | - Month (1 - 12)
|
||||
* - Age (0 - 3)
|
||||
*/
|
||||
|
||||
#define RT11_HOME 1 /* Home block is always 1 */
|
||||
#define RT11_DSSTART 6 /* Start of directory segs */
|
||||
#define RT11_BLOCKSIZE 512 /* Size of a data block on disk */
|
||||
|
||||
#define RT11_SYSVER "V05"
|
||||
#define RT11_VOLID "RT11A "
|
||||
#define RT11_OWNER " "
|
||||
#define RT11_SYSID "DECRT11A "
|
||||
|
||||
/*
|
||||
* Partition sizes. The last block os a maximum sized partition is unused.
|
||||
* The minimum size is based on a file system having 1 directory segment and
|
||||
* 1 data block! Is this reasonable?
|
||||
*/
|
||||
#define RT11_MAXPARTSZ 0200000 /* Max partition size */
|
||||
#define RT11_MINPARTSZ 0000011 /* Min partition size */
|
||||
|
||||
#define RT11_RL02SZ 20480 /* Size of an RL02 drive */
|
||||
#define RT11_RX20SZ 1024 /* Size of an RX20 floppy drive */
|
||||
|
||||
#define RT11_HB_BBLOCK 0000 /* Bad block replacement tbl */
|
||||
#define RT11_HB_RESTORE 0102 /* INIT/RESTORE data area */
|
||||
#define RT11_HB_BUP 0125 /* BUP info area */
|
||||
#define RT11_HB_PCS 0351 /* Pack cluster size */
|
||||
#define RT11_HB_FIRST 0352 /* First directory segment */
|
||||
#define RT11_HB_SYSVER 0353 /* System version */
|
||||
#define RT11_HB_VOLID 0354 /* Volume identification */
|
||||
#define RT11_HB_OWNER 0362 /* Owner name */
|
||||
#define RT11_HB_SYSID 0370 /* System identification */
|
||||
#define RT11_HB_CHKSUM 0377 /* Checksum */
|
||||
|
||||
#define RT11_DH_COUNT 0000 /* # of directory segments */
|
||||
#define RT11_DH_NEXT 0001 /* Next logical segment # */
|
||||
#define RT11_DH_HIGHEST 0002 /* Highest segment # in use */
|
||||
#define RT11_DH_EXTRA 0003 /* Extra bytes/dir. entry */
|
||||
#define RT11_DH_START 0004 /* Block # for segment start */
|
||||
#define RT11_DH_SIZE 0005 /* Size of header */
|
||||
|
||||
#define RT11_DS_SIZE 512 /* Directory segment size */
|
||||
#define RT11_DS_DISPACE (RT11_DS_SIZE - RT11_DH_SIZE)
|
||||
#define RT11_DS_MAX 31 /* Max # of directory segments */
|
||||
|
||||
#define RT11_DI_STATUS 0000 /* Status word */
|
||||
#define RT11_DI_FNAME1 0001 /* File name (chars 1 - 3) */
|
||||
#define RT11_DI_FNAME2 0002 /* File name (chars 4 - 6) */
|
||||
#define RT11_DI_FTYPE 0003 /* File type (1 - 3 chars) */
|
||||
#define RT11_DI_LENGTH 0004 /* Total file length */
|
||||
#define RT11_DI_JOB_CHN 0005 /* Channel # */
|
||||
#define RT11_DI_CREATE 0006 /* Date of creation */
|
||||
#define RT11_DI_SIZE 0007 /* Default entry size */
|
||||
|
||||
#define RT11_E_PRE 000020 /* Prefix block indicator */
|
||||
#define RT11_E_TENT 000400 /* Tentative file */
|
||||
#define RT11_E_MPTY 001000 /* Empty area */
|
||||
#define RT11_E_PERM 002000 /* Permanent file */
|
||||
#define RT11_E_EOS 004000 /* End of segment marker */
|
||||
#define RT11_E_READ 040000 /* Protected from .WRITE */
|
||||
#define RT11_E_PROT 100000 /* Protected permanent file */
|
||||
|
||||
#define RT11EOS(v) (((v) & RT11_E_EOS) != 0)
|
||||
|
||||
#define RT11_DW_YEAR 0000037 /* Year */
|
||||
#define RT11_DW_DAY 0001740 /* Day */
|
||||
#define RT11_DW_MONTH 0036000 /* Month */
|
||||
#define RT11_DW_AGE 0140000 /* Age */
|
||||
|
||||
/*
|
||||
* Structure to describe a filename. Asterisks may be used as wild card
|
||||
* characters for the 2 components of a filename; name and type.
|
||||
*/
|
||||
struct rt11FileSpec {
|
||||
uint8_t flags; /* Wild card indicators */
|
||||
uint16_t name[2]; /* File name (RAD50) */
|
||||
uint16_t type; /* File type (RAD50) */
|
||||
char fname[6]; /* File name (ASCII) */
|
||||
char ftype[3]; /* File type (ASCII) */
|
||||
};
|
||||
#define RT11_WC_NAME 0001 /* Wild card in name */
|
||||
#define RT11_WC_TYPE 0002 /* Wild card in type */
|
||||
|
||||
#define RT11_M_NONE 0000 /* Wild cards not allowed */
|
||||
#define RT11_M_ALLOW 0001 /* Wild cards allowed */
|
||||
#define RT11_M_NONAME 0002 /* Wild cards allowed */
|
||||
/* If no filename + extension */
|
||||
/* present, default to *.* */
|
||||
/*
|
||||
* Structure to define an open file. This is an RT-11 directory entry along
|
||||
* with sufficient information to be able to write the directory entry back
|
||||
* to disk. Some of the directory information can be created on-the-fly so
|
||||
* will not be stored here.
|
||||
*/
|
||||
struct rt11OpenFile {
|
||||
uint16_t status; /* File status */
|
||||
uint16_t name[2]; /* File name */
|
||||
uint16_t type; /* File type */
|
||||
uint16_t length; /* Blocks written */
|
||||
uint16_t creation; /* Creation date */
|
||||
/* End of directory entry */
|
||||
uint8_t segment; /* Directory segment # */
|
||||
uint16_t offset; /* Directory offset */
|
||||
/* Start of read/write info */
|
||||
enum openMode mode; /* Open mode (read/write) */
|
||||
struct mountedFS *mount; /* Mounted file system descriptor */
|
||||
uint8_t unit; /* Partition number */
|
||||
char *buffer; /* Private buffer for file I/O */
|
||||
uint16_t current; /* Current working block # */
|
||||
uint16_t last; /* Last usable block */
|
||||
uint16_t count; /* Bytes used in current block */
|
||||
uint16_t start; /* Starting block # */
|
||||
};
|
||||
|
||||
/*
|
||||
* RT-11 specific data area.
|
||||
*/
|
||||
struct RT11data {
|
||||
unsigned int blocks; /* Size of container */
|
||||
uint16_t filesystems; /* Max # of filesystems */
|
||||
uint16_t valid[16]; /* Valid partitions */
|
||||
uint16_t maxblk[256]; /* Max block address */
|
||||
uint16_t buf[512]; /* Disk buffer - enough for a */
|
||||
/* directory segment */
|
||||
};
|
||||
#define PARTITIONVALID(d, u) ((d->valid[u / 16] & (1 << (u % 16))) != 0)
|
||||
|
||||
#endif
|
||||
816
converters/fsio/tape.c
Normal file
816
converters/fsio/tape.c
Normal file
@ -0,0 +1,816 @@
|
||||
/*
|
||||
* Copyright (C) 2018 John Forecast. All Rights Reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY JOHN FORECAST "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Support routines for reading/writing SIMH tape container files.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <time.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "fsio.h"
|
||||
|
||||
/*++
|
||||
* t a p e V e r i f y
|
||||
*
|
||||
* Verify that the container format is valid, leaving the tape positioned
|
||||
* at beginning-of-tape.
|
||||
*
|
||||
* Inputs:
|
||||
*
|
||||
* container - pointer open container file
|
||||
* eot - return end-of-tape info here, NUL if not needed
|
||||
*
|
||||
* Outputs:
|
||||
*
|
||||
* None
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* 1 if format is valid, 0 otherwise
|
||||
*
|
||||
--*/
|
||||
int tapeVerify(
|
||||
FILE *container,
|
||||
off_t *eot
|
||||
)
|
||||
{
|
||||
int errorCount = 0, tmSeen = 0;
|
||||
uint32_t meta, header, bc;
|
||||
off_t position;
|
||||
struct stat stat;
|
||||
|
||||
/*
|
||||
* Determine the size of the file.
|
||||
*/
|
||||
fstat(fileno(container), &stat);
|
||||
|
||||
for (;;) {
|
||||
position = ftello(container);
|
||||
|
||||
/*
|
||||
* If we are positioned at the end-of-file, there is a tape mark or
|
||||
* end-of-media marker missing. Treat it as though one is present.
|
||||
*/
|
||||
if (position == stat.st_size)
|
||||
break;
|
||||
|
||||
if (fread(&meta, sizeof(meta), 1, container) != 1)
|
||||
return 0;
|
||||
|
||||
bc = le32toh(meta);
|
||||
|
||||
switch (bc) {
|
||||
case ST_TM:
|
||||
if (++tmSeen <= 1)
|
||||
break;
|
||||
/* Treat second TM in a row as end of medium */
|
||||
/* FALLTHROUGH */
|
||||
|
||||
case ST_EOM:
|
||||
if (fseeko(container, -sizeof(meta), SEEK_CUR) != 0)
|
||||
return 0;
|
||||
|
||||
if (errorCount)
|
||||
printf("mount: Tape contains error records\n");
|
||||
goto done;
|
||||
|
||||
case ST_GAP:
|
||||
break;
|
||||
|
||||
default:
|
||||
/*
|
||||
* Record descriptor
|
||||
*/
|
||||
tmSeen = 0;
|
||||
|
||||
header = bc;
|
||||
if ((bc & ST_ERROR) != 0)
|
||||
errorCount++;
|
||||
if ((bc & ST_MBZ) != 0)
|
||||
return 0;
|
||||
|
||||
bc = RECLEN(bc & ST_LENGTH);
|
||||
|
||||
/*
|
||||
* Check if we are seeking ouside of the file. If so, this is not
|
||||
* a .tap container file.
|
||||
*/
|
||||
if ((position + bc + (2 * sizeof(meta))) > (unsigned long long)stat.st_size)
|
||||
return 0;
|
||||
|
||||
if (fseeko(container, bc, SEEK_CUR) != 0)
|
||||
return 0;
|
||||
if (fread(&meta, sizeof(meta), 1, container) != 1)
|
||||
return 0;
|
||||
|
||||
bc = le32toh(meta);
|
||||
|
||||
if (header != bc)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
done:
|
||||
if (eot != NULL)
|
||||
*eot = ftello(container);
|
||||
|
||||
/*
|
||||
* Position at beginning-of-tape.
|
||||
*/
|
||||
if (fseeko(container, 0, SEEK_SET) == 0)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*++
|
||||
* t a p e G e t P o s i t i o n
|
||||
*
|
||||
* Get the current position of the tape.
|
||||
*
|
||||
* Inputs:
|
||||
*
|
||||
* container - pointer open container file
|
||||
*
|
||||
* Outputs:
|
||||
*
|
||||
* None
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* Current position of the tape
|
||||
*
|
||||
--*/
|
||||
off_t tapeGetPosition(
|
||||
FILE *container
|
||||
)
|
||||
{
|
||||
return ftello(container);
|
||||
}
|
||||
|
||||
/*++
|
||||
* t a p e S e t P o s i t i o n
|
||||
*
|
||||
* Position the tape to a position previously obtained by tapeGetPosition().
|
||||
*
|
||||
* Inputs:
|
||||
*
|
||||
* container - pointer open container file
|
||||
* pos - requested position
|
||||
*
|
||||
* Outputs:
|
||||
*
|
||||
* None
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* 1 if successfully positioned, 0 if error
|
||||
*
|
||||
--*/
|
||||
int tapeSetPosition(
|
||||
FILE *container,
|
||||
off_t pos
|
||||
)
|
||||
{
|
||||
return fseeko(container, pos, SEEK_SET) == 0 ? 1 : 0;
|
||||
}
|
||||
|
||||
/*++
|
||||
* t a p e S k i p R e c o r d F
|
||||
*
|
||||
* Skip over the next record in the forward direction.
|
||||
*
|
||||
* Inputs:
|
||||
*
|
||||
* container - pointer open container file
|
||||
*
|
||||
* Outputs:
|
||||
*
|
||||
* None
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* ST_FAIL - error accessing container file
|
||||
* ST_EOM - end of media detected
|
||||
* ST_TM - tape mark detected
|
||||
* Other - record length (including error flag)
|
||||
*
|
||||
--*/
|
||||
uint32_t tapeSkipRecordF(
|
||||
FILE *container
|
||||
)
|
||||
{
|
||||
return tapeReadRecordLength(container);
|
||||
}
|
||||
|
||||
/*++
|
||||
* t a p e S k i p R e c o r d R
|
||||
*
|
||||
* Skip over the next record in the reverse direction.
|
||||
*
|
||||
* Inputs:
|
||||
*
|
||||
* container - pointer open container file
|
||||
*
|
||||
* Outputs:
|
||||
*
|
||||
* None
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* ST_FAIL - error accessing container file
|
||||
* ST_EOM - end of media detected
|
||||
* ST_TM - tape mark detected
|
||||
* Other - record length (including error flag)
|
||||
*
|
||||
--*/
|
||||
uint32_t tapeSkipRecordR(
|
||||
FILE *container
|
||||
)
|
||||
{
|
||||
return tapeReadRecordLengthReverse(container);
|
||||
}
|
||||
|
||||
/*++
|
||||
* t a p e P e e k R e c o r d L e n g t h
|
||||
*
|
||||
* Get the length of the next record on the tape without actually reading
|
||||
* the data or changing the current position of the tape.
|
||||
*
|
||||
* Inputs:
|
||||
*
|
||||
* container - pointer open container file
|
||||
*
|
||||
* Outputs:
|
||||
*
|
||||
* None
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* ST_FAIL - error accessing the container file
|
||||
* ST_EOM - end of media detected
|
||||
* ST_TM - tape mark detected
|
||||
* Other - record length (including error flag)
|
||||
*
|
||||
--*/
|
||||
uint32_t tapePeekRecordLength(
|
||||
FILE *container
|
||||
)
|
||||
{
|
||||
off_t pos = ftello(container);
|
||||
uint32_t meta;
|
||||
|
||||
if ((fread(&meta, sizeof(meta), 1, container) != 1) ||
|
||||
(fseeko(container, pos, SEEK_SET) != 0))
|
||||
return ST_FAIL;
|
||||
|
||||
return le32toh(meta);
|
||||
}
|
||||
|
||||
/*++
|
||||
* t a p e R e a d R e c o r d
|
||||
*
|
||||
* Read the next record from the tape into the specified buffer. If the
|
||||
* buffer is smaller than the record, the entire record will be consumed,
|
||||
* losing data.
|
||||
*
|
||||
* Inputs:
|
||||
*
|
||||
* container - pointer open container file
|
||||
* buf - pointer to the buffer to receive the data
|
||||
* len - length of the buffer
|
||||
*
|
||||
* Outputs:
|
||||
*
|
||||
* None
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* ST_FAIL - error accessing the container file
|
||||
* ST_EOM - end of media detected
|
||||
* ST_TM - tape mark detected
|
||||
* Other - record length (including error flag)
|
||||
* if the buffer is smaller than the record, the
|
||||
* length returned will be that of the buffer
|
||||
*
|
||||
--*/
|
||||
uint32_t tapeReadRecord(
|
||||
FILE *container,
|
||||
void *buf,
|
||||
int len
|
||||
)
|
||||
{
|
||||
off_t pos = ftello(container);
|
||||
uint32_t meta, bc, erflag, length;
|
||||
|
||||
if (fread(&meta, sizeof(meta), 1, container) != 1)
|
||||
return ST_FAIL;
|
||||
|
||||
bc = le32toh(meta);
|
||||
|
||||
switch (bc) {
|
||||
case ST_EOM:
|
||||
case ST_TM:
|
||||
return bc;
|
||||
|
||||
default:
|
||||
erflag = bc & ST_ERROR;
|
||||
bc &= ST_LENGTH;
|
||||
|
||||
length = (uint32_t)len;
|
||||
if (bc < length)
|
||||
length = bc;
|
||||
|
||||
if (fread(buf, sizeof(uint8_t), length, container) != length)
|
||||
return ST_FAIL;
|
||||
|
||||
/*
|
||||
* Now position the file after this record.
|
||||
*/
|
||||
pos += RECLEN(bc) + (2 * sizeof(meta));
|
||||
if (fseeko(container, pos, SEEK_SET) != 0)
|
||||
return ST_FAIL;
|
||||
|
||||
return erflag | length;
|
||||
}
|
||||
return ST_FAIL;
|
||||
}
|
||||
|
||||
/*++
|
||||
* t a p e R e a d R e c o r d L e n g t h
|
||||
*
|
||||
* Get the length of the next record on the tape without actually reading
|
||||
* the data. The tape will be positioned at the start of the next record.
|
||||
*
|
||||
* Inputs:
|
||||
*
|
||||
* container - pointer open container file
|
||||
*
|
||||
* Outputs:
|
||||
*
|
||||
* None
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* ST_FAIL - error accessing container file
|
||||
* ST_EOM - end of media detected
|
||||
* ST_TM - tape mark detected
|
||||
* Other - record length (including error flag)
|
||||
*
|
||||
--*/
|
||||
uint32_t tapeReadRecordLength(
|
||||
FILE *container
|
||||
)
|
||||
{
|
||||
off_t pos = ftello(container);
|
||||
uint32_t meta, bc, erflag;
|
||||
|
||||
if (fread(&meta, sizeof(meta), 1, container) != 1)
|
||||
return ST_FAIL;
|
||||
|
||||
bc = le32toh(meta);
|
||||
|
||||
switch (bc) {
|
||||
case ST_EOM:
|
||||
case ST_TM:
|
||||
return bc;
|
||||
|
||||
default:
|
||||
erflag = bc & ST_ERROR;
|
||||
bc &= ST_LENGTH;
|
||||
|
||||
/*
|
||||
* Now position the file after this record.
|
||||
*/
|
||||
pos += RECLEN(bc) + (2 * sizeof(meta));
|
||||
if (fseeko(container, pos, SEEK_SET) != 0)
|
||||
return ST_FAIL;
|
||||
|
||||
return erflag | bc;
|
||||
}
|
||||
return ST_FAIL;
|
||||
}
|
||||
|
||||
/*++
|
||||
* t a p e R e a d R e c o r d L e n g t h R e v e r s e
|
||||
*
|
||||
* Get the length of the previous record on the tape without actually reading
|
||||
* the data. The tape will be positioned at the start of the previous record.
|
||||
*
|
||||
* Inputs:
|
||||
*
|
||||
* container - pointer open container file
|
||||
*
|
||||
* Outputs:
|
||||
*
|
||||
* None
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* ST_FAIL - error accessing container file
|
||||
* ST_EOM - end of media detected
|
||||
* ST_TM - tape mark detected
|
||||
* Other - record length (including error flag)
|
||||
*
|
||||
--*/
|
||||
uint32_t tapeReadRecordLengthReverse(
|
||||
FILE *container
|
||||
)
|
||||
{
|
||||
uint32_t meta, bc, erflag;
|
||||
off_t delta;
|
||||
|
||||
if ((fseeko(container, -sizeof(meta), SEEK_CUR) != 0) ||
|
||||
(fread(&meta, sizeof(meta), 1, container) != 1))
|
||||
return ST_FAIL;
|
||||
|
||||
bc = le32toh(meta);
|
||||
|
||||
switch (bc) {
|
||||
case ST_EOM:
|
||||
case ST_TM:
|
||||
if (fseeko(container, -sizeof(meta), SEEK_CUR) != 0)
|
||||
return ST_FAIL;
|
||||
return bc;
|
||||
|
||||
default:
|
||||
erflag = bc & ST_ERROR;
|
||||
bc &= ST_LENGTH;
|
||||
|
||||
/*
|
||||
* Now position the file before this record.
|
||||
*/
|
||||
delta = RECLEN(bc) + (2 * sizeof(meta));
|
||||
if (fseeko(container, -delta, SEEK_CUR) != 0)
|
||||
return ST_FAIL;
|
||||
|
||||
return erflag | bc;
|
||||
}
|
||||
return ST_FAIL;
|
||||
}
|
||||
|
||||
/*++
|
||||
* t a p e W r i t e R e c o r d
|
||||
*
|
||||
* Write a record to the tape at it's current position leaving the tape
|
||||
* positioned after the newly written record.
|
||||
*
|
||||
* Inputs:
|
||||
*
|
||||
* container - pointer open container file
|
||||
* buf - pointer to the record to be written
|
||||
* len - length of the record
|
||||
*
|
||||
* Outputs:
|
||||
*
|
||||
* None
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* 1 if record was successfully written, 0 otherwise
|
||||
*
|
||||
--*/
|
||||
int tapeWriteRecord(
|
||||
FILE *container,
|
||||
void *buf,
|
||||
int len
|
||||
)
|
||||
{
|
||||
uint32_t meta = htole16(len);
|
||||
int datalen = (len + 1) & ~1;
|
||||
|
||||
if ((fwrite(&meta, sizeof(meta), 1, container) != 1) ||
|
||||
(fwrite(buf, datalen, 1, container) != 1) ||
|
||||
(fwrite(&meta, sizeof(meta), 1, container) != 1))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*++
|
||||
* t a p e W r i t e E O M
|
||||
*
|
||||
* Write an end-of-media record to the tape at it's current position and,
|
||||
* optionally, backup the tape to before the newly written record.
|
||||
*
|
||||
* Inputs:
|
||||
*
|
||||
* container - pointer open container file
|
||||
* backup - if 1, position the tape before the new record
|
||||
*
|
||||
* Outputs:
|
||||
*
|
||||
* None
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* 1 if EOM record successfully written, 0 otherwise
|
||||
*
|
||||
--*/
|
||||
int tapeWriteEOM(
|
||||
FILE *container,
|
||||
int backup
|
||||
)
|
||||
{
|
||||
uint32_t eom = htole32(ST_EOM);
|
||||
|
||||
if (fwrite(&eom, sizeof(eom), 1, container) != 1)
|
||||
return 0;
|
||||
|
||||
if (backup)
|
||||
if (fseeko(container, -sizeof(eom), SEEK_CUR) != 0)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*++
|
||||
* t a p e W r i t e T M
|
||||
*
|
||||
* Write a tape mark record to the tape at it's current position.
|
||||
*
|
||||
* Inputs:
|
||||
*
|
||||
* container - pointer open container file
|
||||
*
|
||||
* Outputs:
|
||||
*
|
||||
* None
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* 1 if EOM record successfully written, 0 otherwise
|
||||
*
|
||||
--*/
|
||||
int tapeWriteTM(
|
||||
FILE *container
|
||||
)
|
||||
{
|
||||
uint32_t tm = htole32(ST_TM);
|
||||
|
||||
if (fwrite(&tm, sizeof(tm), 1, container) != 1)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*++
|
||||
* t a p e E O M
|
||||
*
|
||||
* Position the tape to the end of media so that a subsequent write will
|
||||
* append a file to the tape.
|
||||
*
|
||||
* Inputs:
|
||||
*
|
||||
* container - pointer open container file
|
||||
* eot - pointer to end-of-tape position, NULL if
|
||||
* not available
|
||||
*
|
||||
* Outputs:
|
||||
*
|
||||
* None
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* 1 if tape successfully positioned, 0 otherwise
|
||||
*
|
||||
--*/
|
||||
int tapeEOM(
|
||||
FILE *container,
|
||||
off_t *eot
|
||||
)
|
||||
{
|
||||
int whence = eot == NULL ? SEEK_END : SEEK_SET;
|
||||
off_t pos = eot == NULL ? 0 : *eot;
|
||||
uint32_t bc1, bc2;
|
||||
|
||||
/*
|
||||
* Move to the end of the tape and then look backwards to see how it is
|
||||
* terminated.
|
||||
*/
|
||||
if (fseeko(container, pos, whence) == 0) {
|
||||
if (ftello(container) == 0) {
|
||||
/*
|
||||
* Empty file, we are correctly positioned.
|
||||
*/
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((bc1 = tapeReadRecordLengthReverse(container)) == ST_FAIL)
|
||||
return 0;
|
||||
|
||||
if ((bc1 == ST_EOM) || (bc1 == ST_TM)) {
|
||||
if (ftello(container) == 0) {
|
||||
/*
|
||||
* Only ST_EOM or ST_TM present, we are correctly positioned.
|
||||
*/
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((bc2 = tapeReadRecordLengthReverse(container)) == ST_FAIL)
|
||||
return 0;
|
||||
|
||||
if (bc2 == ST_TM) {
|
||||
if (ftello(container) == 0) {
|
||||
/*
|
||||
* Only ST_TM followed by ST_TM or ST_EOM, we are correctly
|
||||
* positioned
|
||||
*/
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* ST_TM followed by ST_TM or ST_EOM with at least one data block
|
||||
* present, skip over the initial ST_TM.
|
||||
*/
|
||||
if (fseeko(container, sizeof(uint32_t), SEEK_CUR) == 0)
|
||||
return 1;
|
||||
} else {
|
||||
/*
|
||||
* Only a single ST_TM at the end of the container file. This
|
||||
* indicates that there is a missing ST_TM or ST_EOM. Position
|
||||
* the tape at the logical end-of-tape so that any subsequent file
|
||||
* write will fix the problem.
|
||||
*/
|
||||
if (fseeko(container, pos, whence) == 0)
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*++
|
||||
* t a p e R e w i n d
|
||||
*
|
||||
* Rewind the tape.
|
||||
*
|
||||
* Inputs:
|
||||
*
|
||||
* container - pointer open container file
|
||||
*
|
||||
* Outputs:
|
||||
*
|
||||
* None
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* None
|
||||
*
|
||||
--*/
|
||||
void tapeRewind(
|
||||
FILE *container
|
||||
)
|
||||
{
|
||||
fseeko(container, 0, SEEK_SET);
|
||||
}
|
||||
|
||||
/*++
|
||||
* t a p e S k i p F o r w a r d
|
||||
*
|
||||
* Skip forward over a number of files. If end-of-media is reached, the skip
|
||||
* operation will terminate early.
|
||||
*
|
||||
* Inputs:
|
||||
*
|
||||
* container - pointer open container file
|
||||
* count - # of files to skip
|
||||
*
|
||||
* Outputs:
|
||||
*
|
||||
* None
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* 1 if skip was successful, 0 otherwise
|
||||
*
|
||||
--*/
|
||||
int tapeSkipForward(
|
||||
FILE *container,
|
||||
unsigned long count
|
||||
)
|
||||
{
|
||||
unsigned long i;
|
||||
uint32_t bc;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
/*
|
||||
* Peek at the next record. If it's a tape mark or end-of-media there
|
||||
* are not more files to skip.
|
||||
*/
|
||||
switch (tapePeekRecordLength(container)) {
|
||||
case ST_FAIL:
|
||||
return 0;
|
||||
|
||||
case ST_TM:
|
||||
case ST_EOM:
|
||||
return 1;
|
||||
}
|
||||
/*
|
||||
* Skip forward over 1 file.
|
||||
*/
|
||||
do {
|
||||
switch (bc = tapeReadRecordLength(container)) {
|
||||
case ST_FAIL:
|
||||
return 0;
|
||||
|
||||
case ST_EOM:
|
||||
if (fseeko(container, -sizeof(uint32_t), SEEK_CUR) != 0)
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
} while ((bc != ST_TM) && (bc != ST_EOM));
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*++
|
||||
* t a p e S k i p R e v e r s e
|
||||
*
|
||||
* Skip backwards over a number of files. If beginning-of-tape is reached,
|
||||
* the skip operation will terminate early.
|
||||
*
|
||||
* Inputs:
|
||||
*
|
||||
* container - pointer open container file
|
||||
* count - # of files to skip
|
||||
*
|
||||
* Outputs:
|
||||
*
|
||||
* None
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* 1 if skip was successful, 0 otherwise
|
||||
*
|
||||
--*/
|
||||
int tapeSkipReverse(
|
||||
FILE *container,
|
||||
unsigned long count
|
||||
)
|
||||
{
|
||||
unsigned long i;
|
||||
uint32_t bc;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
/*
|
||||
* If we are at beginning-of-tape, there are no more files to skip.
|
||||
*/
|
||||
if (ftello(container) == 0)
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* If we are not at the beginning of tape, the previous record should
|
||||
* be a tape mark.
|
||||
*/
|
||||
if (tapeReadRecordLengthReverse(container) != ST_TM)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Now skip over the remainder of the file.
|
||||
*/
|
||||
do {
|
||||
if ((bc = tapeReadRecordLengthReverse(container)) == ST_FAIL)
|
||||
return 0;
|
||||
} while ((bc != ST_TM) && (ftello(container) != 0));
|
||||
|
||||
/*
|
||||
* Skip over the tape mark since it marks the end of the previous file.
|
||||
*/
|
||||
if (bc == ST_TM) {
|
||||
if (fseeko(container, sizeof(uint32_t), SEEK_CUR) != 0)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
73
converters/fsio/tape.h
Normal file
73
converters/fsio/tape.h
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (C) 2018 John Forecast. All Rights Reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY JOHN FORECAST "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef __TAPE_H__
|
||||
#define __TAPE_H__
|
||||
|
||||
/*
|
||||
* Metadata markers
|
||||
*/
|
||||
#define ST_EOM 0xFFFFFFFF /* end of medium */
|
||||
#define ST_GAP 0xFFFFFFFE /* erase gap */
|
||||
#define ST_TM 0x00000000 /* tape mark */
|
||||
|
||||
/*
|
||||
* Special code for reporting errors. If actually read from a container
|
||||
* file, this would be considered an error.
|
||||
*/
|
||||
#define ST_FAIL 0xFEFEFEFE
|
||||
|
||||
/*
|
||||
* Record length field layout
|
||||
*/
|
||||
#define ST_ERROR 0x80000000 /* record contains an error */
|
||||
#define ST_MBZ 0x7F000000 /* must be zero */
|
||||
#define ST_LENGTH 0x00FFFFFF /* record length */
|
||||
|
||||
/*
|
||||
* Data in the .tap container file is rounded up to an even number of bytes
|
||||
*/
|
||||
#define RECLEN(c) (((c) + 1) & ~1)
|
||||
|
||||
extern int tapeVerify(FILE *, off_t *);
|
||||
extern off_t tapeGetPosition(FILE *);
|
||||
extern int tapeSetPosition(FILE *, off_t);
|
||||
extern uint32_t tapeSkipRecordF(FILE *);
|
||||
extern uint32_t tapeSkipRecordR(FILE *);
|
||||
extern uint32_t tapePeekRecordLength(FILE *);
|
||||
extern uint32_t tapeReadRecord(FILE *, void *, int);
|
||||
extern uint32_t tapeReadRecordLength(FILE *);
|
||||
extern uint32_t tapeReadRecordLengthReverse(FILE *);
|
||||
extern int tapeWriteRecord(FILE *, void *, int);
|
||||
extern int tapeWriteEOM(FILE *, int);
|
||||
extern int tapeWriteTM(FILE *);
|
||||
extern int tapeEOM(FILE *, off_t *);
|
||||
extern void tapeRewind(FILE *);
|
||||
extern int tapeSkipForward(FILE *, unsigned long);
|
||||
extern int tapeSkipReverse(FILE *, unsigned long);
|
||||
|
||||
#endif
|
||||
Loading…
x
Reference in New Issue
Block a user