FDIO: Various improvements

This commit is contained in:
John Forecast 2019-05-15 09:15:18 -07:00 committed by Mark Pizzolato
parent 5117bd4d7c
commit cfeb0e42da
8 changed files with 235 additions and 61 deletions

View File

@ -1,5 +1,5 @@
#CFLAGS=-O2 -Wall -Wshadow -Wextra -pedantic -Woverflow -Wstrict-overflow
CFLAGS=-g -Wall -Wshadow -Wextra -pedantic -Woverflow -Wstrict-overflow
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

View File

@ -1,4 +1,4 @@
.TH FSIO-RT11 1 "December 28,2018" "FFS I/O - RT-11"
.TH FSIO-RT11 1 "May 15,2019" "FFS I/O - RT-11"
.SH NAME
fsio-rt11 \- Foreign File System I/O - RT-11
.br
@ -6,6 +6,26 @@ fsio-rt11 \- Foreign File System I/O - RT-11
\fBfsio\fP allows access to RT-11 file systems using the file system type
"\fIrt11\fP"
.br
.SH RT-11 VERSIONS
There were 5 major versions of RT-11 released. Versions 1 and 2 did not use
the home block (block 1) to indicate that the on-disk file structure was RT-11
format. The remaining 3 versions wrote a signature on the home block
including the file system version in use. In order to access a version 1 or
version 2 container file, the \fI"-f"\fP switch must be used on the
\fI"mount"\fP command to force \fBfsio\fP
to bypass the home block checks. While \fBfsio\fP will use a set of
heuristics to verify the integrity of the RT-11 file structure it is possible
that an invalid file structure will satisfy the checks and cause \fBfsio\fP to
fail. Do not use the \fI"-f"\fP switch other than to mount version 1 or
version 2 file systems.
.br
The VMS exchange utility may be used to initialize an RT-11 volume but writes
it's own unique signature in the home block. \fBfsio\fP is able to correctly
handle this signature.
.SH LOGICAL DISKS
\fBfsio\fP can be used to access an RT-11 logical disk if the file has been
copied to the host file system.
.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
@ -18,12 +38,14 @@ 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
.RS
.TP
\fIrl02\fP \- RL02 image (10MB, 20480 blocks)
.br
.TP
\fIrx20\fP \- RX20 image (512KB, 1024 blocks)
.br
.RE
.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

View File

@ -1,4 +1,4 @@
.TH FSIO 1 "December 25,2018" "Foreign File System I/O"
.TH FSIO 1 "May 15,2019" "Foreign File System I/O"
.SH NAME
fsio \- Foreign File System I/O
.SH SYNOPSIS
@ -76,7 +76,7 @@ The following commands are only accepted by file systems which are on magtape de
.br
.SH COMMANDS
.TP
.B "\fImount\fP [-drx] dev[:] file type"
.B "\fImount\fP [-dfrx] dev[:] file type"
Make the container file available to fsio.
.br
.RS
@ -89,6 +89,8 @@ Make the container file available to fsio.
.br
.B " Only available if built with DEBUG enabled"
.br
.B "\fI\-f\fP \- bypass home block validation (RT-11 only)"
.br
.B "\fI\-r\fP \- mount file system read-only"
.br
.B "\fI\-x\fP \- dosmt will use extended filenames when writing"

View File

@ -310,9 +310,9 @@ struct command {
cmd_t func; /* Command execution function */
} cmdTable[] = {
#ifdef DEBUG
{ "mount", OPTIONS("drx"), 3, 3, 0, doMount },
{ "mount", OPTIONS("dfrx"), 3, 3, 0, doMount },
#else
{ "mount", OPTIONS("rx"), 3, 3, 0, doMount },
{ "mount", OPTIONS("frx"), 3, 3, 0, doMount },
#endif
{ "umount", NULL, 1, 1, 0, doUmount },
{ "newfs", OPTIONS("t:"), 2, 2, 0, doNewfs },

View File

@ -87,12 +87,14 @@ Full command syntax:
1. mount
mount [-dr] dev[:] container type
mount [-dfr] 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
-f Force the mount to happen even if we are unable to completely
validate the container file format
-r If present, the file system is only available for read access
dev[:] User supplied name to be used for accessing files within the

View File

@ -14,10 +14,6 @@ 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
--------------------------

View File

@ -474,7 +474,7 @@ int rt11ReadDirSegment(
)
{
struct RT11data *data = &mount->rt11data;
unsigned int block = RT11_DSSTART + ((segment - 1) * 2);
unsigned int block = data->first[unit] + ((segment - 1) * 2);
if (rt11ReadBlock(mount, unit, block, &data->buf[0]) != 0)
if (rt11ReadBlock(mount, unit, block + 1, &data->buf[256]) != 0)
@ -510,7 +510,7 @@ int rt11WriteDirSegment(
)
{
struct RT11data *data = &mount->rt11data;
unsigned int block = RT11_DSSTART + ((segment - 1) * 2);
unsigned int block = data->first[unit] + ((segment - 1) * 2);
if (rt11WriteBlock(mount, unit, block, &data->buf[0]) != 0)
if (rt11WriteBlock(mount, unit, block + 1, &data->buf[256]) != 0)
@ -1353,10 +1353,10 @@ static void info(
}
/*++
* v a l i d a t e
* p a r t i t i o n T y p e
*
* Verify that a partition contains a valid RT-11 filesystem. First verify
* that the checksum is correct and then that the ID fields are correct.
* Determine the type of the partition whose home block is in the mount
* point specific buffer.
*
* Inputs:
*
@ -1365,39 +1365,156 @@ static void info(
*
* Outputs:
*
* The mount point specific buffer will be overwritten.
* ...
*
* Returns:
*
* 1 if file system is valid, 0 otherwise
* partition type:
*
* RT11_NOPART - Not a valid RT11 partition
* RT11_SINGLE - 1 partition supported per disk
* RT11_MULTI - Multiple partitions supported per disk
*
--*/
static int validate(
static int partitionType(
struct mountedFS *mount,
uint8_t unit
)
{
struct RT11data *data = &mount->rt11data;
uint16_t i, checksum = 0;
if (rt11ReadBlock(mount, unit, RT11_HOME, NULL) == 0)
return 0;
if (strncmp((char *)&data->buf[RT11_HB_SYSID], RT11_SYSID, strlen(RT11_SYSID)) == 0) {
uint16_t type = le16toh(data->buf[RT11_HB_SYSVER]);
/*
* Compute the checksum over the Home block.
*/
for (i = 0; i < 255; i++)
checksum += le16toh(data->buf[i]);
if (unit == 0) {
if ((type == RT11_SYSVER_V3A) || (type == RT11_SYSVER_V04))
return RT11_SINGLE;
}
if (checksum == le16toh(data->buf[255])) {
if ((le16toh(data->buf[RT11_HB_PCS]) == 1) &&
(le16toh(data->buf[RT11_HB_FIRST]) == RT11_DSSTART) &&
((strncmp((char *)&data->buf[RT11_HB_SYSID],
RT11_SYSID, strlen(RT11_SYSID))) == 0))
return 1;
if (type == RT11_SYSVER_V05)
return RT11_MULTI;
}
return 0;
if (strncmp((char *)&data->buf[RT11_HB_SYSID], RT11_VMSSYSID, strlen(RT11_VMSSYSID)) == 0)
return RT11_SINGLE;
return RT11_NOPART;
}
/*++
* v a l i d a t e
*
* Verify that a partition contains a valid RT-11 filesystem. First verify
* that the ID fields are correct, then walk the directory structure to
* make sure that we are looking at a valid RT-11 partition.
*
* Inputs:
*
* mount - pointer to a mounted file system descriptor
* unit - partition number
* blocks - return the actual size of the partition here
* first - return first directory segment block # here
*
* Outputs:
*
* The mount point specific buffer will be overwritten.
*
* Returns:
*
* partition type:
*
* RT11_NOPART - Not a valid RT11 partition
* RT11_SINGLE - 1 partition supported per disk
* RT11_MULTI - Multiple partitions supported per disk
*
--*/
static int validate(
struct mountedFS *mount,
uint8_t unit,
uint16_t *blocks,
uint16_t *first
)
{
struct RT11data *data = &mount->rt11data;
int type = RT11_SINGLE;
uint16_t entrysz, position, dsseg = 1;
uint16_t seg_count, seg_highest, highest = 0;
uint8_t seen[RT11_DS_MAX + 1];
if (rt11ReadBlock(mount, unit, RT11_HOME, NULL) == 0)
return RT11_NOPART;
if (!SWISSET('f')) {
if ((type = partitionType(mount, unit)) == RT11_NOPART)
return RT11_NOPART;
*first = le16toh(data->buf[RT11_HB_FIRST]);
} else *first = RT11_DSSTART;
memset(seen, 0, sizeof(seen));
/*
* Now walk the directory to validate it's integrity.
*/
do {
uint16_t off = RT11_DH_SIZE;
if (rt11ReadDirSegment(mount, unit, dsseg) == 0)
return RT11_NOPART;
/*
* Make sure we only look at each directory segment once - we want to
* avoid looping up with invalid input.
*/
if (seen[dsseg]++ != 0)
return RT11_NOPART;
entrysz = RT11_DI_SIZE + (le16toh(data->buf[RT11_DH_EXTRA]) >> 1);
position = le16toh(data->buf[RT11_DH_START]);
if (dsseg == 1) {
seg_count = le16toh(data->buf[RT11_DH_COUNT]);
seg_highest = le16toh(data->buf[RT11_DH_HIGHEST]);
if ((seg_highest > RT11_DS_MAX) || (seg_highest > seg_count))
return RT11_NOPART;
}
if (seg_count != le16toh(data->buf[RT11_DH_COUNT]))
return RT11_NOPART;
/*
* Loop until we see and end-of-segment marker or there is no room for
* another directory entry.
*/
while (!RT11EOS(le16toh(data->buf[off + RT11_DI_STATUS])) &&
((RT11_DS_SIZE - off) >= entrysz)) {
uint16_t status = le16toh(data->buf[off + RT11_DI_STATUS]);
if ((status & RT11_E_MPTY) != 0)
break;
/*
* Within each directory segment the base address should never
* decrease.
*/
if (((position + le16toh(data->buf[off + RT11_DI_LENGTH])) & 0xFFFF) < position)
return RT11_NOPART;
position += le16toh(data->buf[off + RT11_DI_LENGTH]);
off += entrysz;
}
if (position > highest)
highest = position;
dsseg = le16toh(data->buf[RT11_DH_NEXT]);
if (dsseg > seg_highest)
return RT11_NOPART;
} while (dsseg != 0);
*blocks = highest;
return type;
}
/*++
@ -1570,41 +1687,36 @@ static int rt11Mount(
memset(&data->valid, 0, sizeof(data->valid));
if (fstat(fileno(mount->container), &stat) == 0) {
uint16_t i, count, lastsz, validcount;
uint16_t i, count, lastsz, validcount = 0;;
data->blocks = stat.st_size / RT11_BLOCKSIZE;
count = data->blocks / RT11_MAXPARTSZ;
lastsz = data->blocks % RT11_MAXPARTSZ;
validcount = count;
if (lastsz >= RT11_MINPARTSZ)
count++;
/*
* Check each file system for validity.
*/
for (i = 0; i < count; i++) {
int type;
/*
* Assume valid
* Assume valid and maximal size
*/
data->valid[i / 16] |= 1 << (i % 16);
data->maxblk[i] = RT11_MAXPARTSZ - 1;
if (validate(mount, i) == 0) {
data->valid[i / 16] &= ~(1 << (i % 16));
validcount--;
}
}
type = validate(mount, i, &data->maxblk[i], &data->first[i]);
/*
* Check for a small partition to complete the disk
*/
if (lastsz >= RT11_MINPARTSZ) {
data->valid[count / 16] |= 1 << (count % 16);
data->maxblk[count] = lastsz;
if (type != RT11_NOPART)
validcount++;
else data->valid[i / 16] &= ~(1 << (i % 16));
if (validate(mount, count) == 0)
data->valid[count / 16] &= ~(1 << (count % 16));
else validcount++;
if (type == RT11_SINGLE)
break;
}
data->filesystems = validcount;
@ -1642,15 +1754,46 @@ static int rt11Mount(
dsseg = le16toh(data->buf[RT11_DH_NEXT]);
} while (dsseg != 0);
if (!quiet)
printf("%s%o:\n"
" Total blocks: %5d, Free blocks: %5d\n"
if (!quiet) {
char vers[4], *version = NULL;
if (rt11ReadBlock(mount, i, RT11_HOME, NULL) == 0)
return 0;
/*
* Special handling of volumes created by non-RT-11 systenms
* (e.g. VMS Exchange).
*/
if (strncmp((char *)&data->buf[RT11_HB_SYSID], RT11_VMSSYSID, strlen(RT11_VMSSYSID)) == 0) {
r50Asc(le16toh(data->buf[RT11_HB_SYSVER]), vers);
version = vers;
} else {
switch (le16toh(data->buf[RT11_HB_SYSVER])) {
case RT11_SYSVER_V3A:
version = "V3A";
break;
case RT11_SYSVER_V04:
version = "V04";
break;
case RT11_SYSVER_V05:
version = "V05";
break;
}
}
printf("%s%o:\n", mount->name, i);
if (version != NULL)
printf(" Version: %s, System ID: %12s\n",
version, (char *)&data->buf[RT11_HB_SYSID]);
printf(" Total blocks: %5d, Free blocks: %5d\n"
" Directory segments: %2d (Highest %d)\n"
" Extra bytes/directory entry: %d\n",
mount->name, i, data->maxblk[i] + 1, freeblks,
le16toh(data->buf[RT11_DH_COUNT]),
highest,
data->maxblk[i] + 1, freeblks,
le16toh(data->buf[RT11_DH_COUNT]), highest,
le16toh(data->buf[RT11_DH_EXTRA]));
}
validcount--;
}
return 1;
@ -1767,7 +1910,7 @@ static int rt11Newfs(
data->buf[RT11_HB_PCS] = htole16(1);
data->buf[RT11_HB_FIRST] = htole16(RT11_DSSTART);
data->buf[RT11_HB_SYSVER] = htole16(ascR50(RT11_SYSVER));
data->buf[RT11_HB_SYSVER] = htole16(RT11_SYSVER_V05);
strncpy((char *)&data->buf[RT11_HB_VOLID], RT11_VOLID, strlen(RT11_VOLID));
strncpy((char *)&data->buf[RT11_HB_OWNER], RT11_OWNER, strlen(RT11_OWNER));
strncpy((char *)&data->buf[RT11_HB_SYSID], RT11_SYSID, strlen(RT11_SYSID));

View File

@ -167,10 +167,18 @@
#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_SYSVER_V3A 36521
#define RT11_SYSVER_V04 36434
#define RT11_SYSVER_V05 36435
#define RT11_NOPART 0 /* Not a valid partition */
#define RT11_SINGLE 1 /* Single partition per disk */
#define RT11_MULTI 2 /* Multiple partitions per disk */
#define RT11_VOLID "RT11A "
#define RT11_OWNER " "
#define RT11_SYSID "DECRT11A "
#define RT11_VMSSYSID "DECVMSEXCHNG" /* VMS exchange created volume */
/*
* Partition sizes. The last block os a maximum sized partition is unused.
@ -178,7 +186,7 @@
* 1 data block! Is this reasonable?
*/
#define RT11_MAXPARTSZ 0200000 /* Max partition size */
#define RT11_MINPARTSZ 0000011 /* Min partition size */
#define RT11_MINPARTSZ 0000010 /* Min partition size */
#define RT11_RL02SZ 20480 /* Size of an RL02 drive */
#define RT11_RX20SZ 1024 /* Size of an RX20 floppy drive */
@ -282,6 +290,7 @@ struct RT11data {
uint16_t filesystems; /* Max # of filesystems */
uint16_t valid[16]; /* Valid partitions */
uint16_t maxblk[256]; /* Max block address */
uint16_t first[256]; /* First directory block */
uint16_t buf[512]; /* Disk buffer - enough for a */
/* directory segment */
};