Microsoft Windows10上のsimh V3.8-1 VAX.EXEを用いてOpenVMS V7.2の環境を作成しています。OpenVMS側からWindows10側にファイルを持ってくる方法を考えてみました。OpenVMS側ではTU-81で磁気テープにファイルを書き出せば、実はsimhにおける仮想磁気テープファイルとしてWindows10側でアクセスできます。この方法で何でもファイルを持ってこられるわけではないと思いますが、少なくともテキストファイルならば問題ないでしょう。
OpenVMSがTU-81に書き込む際にはANSI X3.27で規定されたフォーマットになっているようです。ここから、最低限としてテキストファイルを取り出せればよいとします。ただし複数ファイルが格納される可能性を考慮しておきます。ファイルを一つずつ取り出しても構わないのですが、ちょっと気をきかせて、TAR形式ファイルに変換しておこうかと思います。
変換スクリプトはWindows10上のWSL2にインストールしてあるUbuntu環境でPythonを使用しました。いろいろと不完全ではあるのですが、仮想磁気テープファイルに格納されているファイルを取り出してTAR形式ファイルに変換するスクリプトができました。
- ANSI X3.27のヘッダ情報を解釈すれば長いファイル名にも対応できるのですが、それは見送りました。
- 当面はテキストファイルだけで良いので、それ以外のファイル形式は未対応としました。
- スクリプトで大域変数を多用していて、あまり良くないのですが、改善するのは将来の課題としました。
作成したスクリプトは、次のようになりました。Pythonでtarfileモジュールを使うと、簡単にTAR形式ファイルを作成できて、ありがたいことです。
#!/usr/bin/python3
import os
import sys
import tarfile
def vol1(r):
# print("{}".format(r[:4]))
# print("\t" "Volume Identifier[{}]".format(r[4:10]))
# print("\t" "Accessibillity[{}]".format(r[10]))
# print("\t" "Owner Identifier[{}]".format(r[37:51]))
# print("\t" "Label-Standard Version[{}]".format(r[79]))
return
def hdr1(r):
global FileName
global fd
FileName = r[4:21].strip()
fd = open(FileName,"w")
# print("{}".format(r[:4]))
# print("\t" "File Identificer[{}]".format(r[4:21]))
# print("\t" "File-Set Identificer[{}]".format(r[21:27]))
# print("\t" "File Section Number[{}]".format(r[27:31]))
# print("\t" "File Sequence Number[{}]".format(r[31:35]))
# print("\t" "Generation Number[{}]".format(r[35:39]))
# print("\t" "Generation Version Number[{}]".format(r[39:41]))
# print("\t" "Creation Date[{}]".format(r[41:47]))
# print("\t" "Expiration Date[{}]".format(r[47:53]))
# print("\t" "Accessibility[{}]".format(r[53]))
# print("\t" "Block Count[{}]".format(r[54:60]))
# print("\t" "System Code[{}]".format(r[60:73]))
return
def hdr2(r):
global RF
RF = r[4]
# print("{}".format(r[:4]))
# print("\t" "Record Format[{}]".format(r[4]))
# print("\t" "Block Length[{}]".format(r[5:10]))
# print("\t" "Record Length[{}]".format(r[10:15]))
# print("\t" "Buffer-Offset Length[{}]".format(r[50:52]))
return
def hdr3(r):
# print("{}".format(r[:4]))
# print("\t" "RMS attribute[{}]".format(r[4:68]))
return
def hdr4(r):
# print("{}".format(r[:4]))
# #print("\t" "Reserved[{}]".format(r[4:79]))
# print("\t" "Filename[{}]".format(r[5:67]))
# print("\t" "Length[{}]".format(r[67:69]))
return
def eof1(r):
fd.close()
tar.add(FileName)
os.remove(FileName)
# print("{}".format(r[:4]))
# print("\t" "File Identificer[{}]".format(r[4:21]))
# print("\t" "File-Set Identificer[{}]".format(r[21:27]))
# print("\t" "File Section Number[{}]".format(r[27:31]))
# print("\t" "File Sequence Number[{}]".format(r[31:35]))
# print("\t" "Generation Number[{}]".format(r[35:39]))
# print("\t" "Generation Version Number[{}]".format(r[39:41]))
# print("\t" "Creation Date[{}]".format(r[41:47]))
# print("\t" "Expiration Date[{}]".format(r[47:53]))
# print("\t" "Accessibility[{}]".format(r[53]))
# print("\t" "Block Count[{}]".format(r[54:60]))
# print("\t" "System Code[{}]".format(r[60:73]))
return
def eof2(r):
# print("{}".format(r[:4]))
# print("\t" "Record Format[{}]".format(r[4]))
# print("\t" "Block Length[{}]".format(r[5:10]))
# print("\t" "Record Length[{}]".format(r[10:15]))
# print("\t" "Buffer-Offset Length[{}]".format(r[50:52]))
return
def eof3(r):
# print("{}".format(r[:4]))
return
def eof4(r):
# print("{}".format(r[:4]))
return
LABELS = {
"VOL1":vol1,
"HDR1":hdr1,
"HDR2":hdr2,
"HDR3":hdr3,
"HDR4":hdr4,
"EOF1":eof1,
"EOF2":eof2,
"EOF3":eof3,
"EOF4":eof4,
}
def fixed(d):
return
def variable(d):
i = 0
while i < len(d):
try:
l = int(d[i:i+4])
except ValueError:
break
# print("{} {:04d} {:04d} {}".format(FileName, i, l, d[i+4:i+l]))
fd.writelines(d[i+4:i+l])
fd.write("\n")
i = i + l
def spanned(d):
return
RECORDS = {
"F":fixed,
"D":variable,
"S":spanned,
}
RF = ""
def readrecord(f):
global TapeMark
len0 = int.from_bytes(f.read(4),'little')
if len0 == 0:
TapeMark += 1
if TapeMark >= 2: raise EOFError
return 0
TapeMark = 0
data = f.read(len0).decode()
len1 = int.from_bytes(f.read(4),'little')
label = data[:4]
if label in LABELS:
LABELS[label](data)
else:
#print(TapeMark, len0, data[:4], data[4:16])
# print("DATA({})".format(len0))
RECORDS[RF](data)
return 0 if len0 != len1 else len0
def readblock(f):
while True:
if readrecord(f) == 0: break
TapeMark = 0
FileName = ""
fd = 0
tar = 0
tar = tarfile.open("tap2tar.tar.gz","w:gz")
with open(sys.argv[1],"rb") as f:
while True:
try:
readblock(f)
except EOFError:
break
tar.close()
#[EOF]