2025-05-06

simhの仮想磁気テープファイルをTAR形式ファイルに変換

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]

0 件のコメント:

コメントを投稿