mirror of
https://github.com/open-simh/simtools.git
synced 2026-01-13 15:27:18 +00:00
FDIO: Various improvements
This commit is contained in:
parent
5117bd4d7c
commit
cfeb0e42da
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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 },
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
--------------------------
|
||||
|
||||
|
||||
@ -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));
|
||||
|
||||
@ -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 */
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user