feat: Start implementation of universal seek cmd

This commit is contained in:
Felicitas Pojtinger
2021-11-17 22:32:29 +01:00
parent 09b7bccc4c
commit 57446132be
3 changed files with 152 additions and 57 deletions

View File

@@ -1,54 +0,0 @@
package main
import (
"archive/tar"
"flag"
"io"
"log"
"os"
)
const (
blockSize = 512
)
func main() {
file := flag.String("file", "test.tar", "Tar file to open")
recordSize := flag.Int("recordSize", 20, "Amount of 512-bit blocks per record")
record := flag.Int("record", 0, "Record to seek too")
block := flag.Int("block", 0, "Block in record to seek too")
flag.Parse()
bytesToSeek := (*recordSize * blockSize * *record) + *block*blockSize
f, err := os.Open(*file)
if err != nil {
panic(err)
}
defer f.Close()
if _, err := f.Seek(int64(bytesToSeek), 0); err != nil {
panic(err)
}
tr := tar.NewReader(f)
for {
hdr, err := tr.Next()
if err != nil {
panic(err)
}
log.Println(hdr)
curr, err := f.Seek(0, io.SeekCurrent)
if err != nil {
panic(err)
}
if currentRecord := ((curr + hdr.Size) / blockSize) / int64(*recordSize); currentRecord > int64(*record) {
break
}
}
}

140
cmd/stfs-seek/main.go Normal file
View File

@@ -0,0 +1,140 @@
package main
import (
"archive/tar"
"bufio"
"flag"
"io"
"log"
"os"
"syscall"
"unsafe"
)
// See https://github.com/benmcclelland/mtio
const (
MTIOCTOP = 0x40086d01 // Do magnetic tape operation
MTSEEK = 22 // Seek to block
MTIOCPOS = 0x80086d03 // Get tape position
blockSize = 512
)
// Operation is struct for MTIOCTOP
type Operation struct {
Op int16 // Operation ID
Pad int16 // Padding to match C structures
Count int32 // Operation count
}
// Position is struct for MTIOCPOS
type Position struct {
BlkNo int64 // Current block number
}
func main() {
file := flag.String("file", "/dev/nst0", "File (tape drive or tar file) to open")
recordSize := flag.Int("recordSize", 20, "Amount of 512-bit blocks per record")
record := flag.Int("record", 0, "Record to seek too")
block := flag.Int("block", 0, "Block in record to seek too")
flag.Parse()
fileDescription, err := os.Stat(*file)
if err != nil {
panic(err)
}
var f *os.File
if fileDescription.Mode().IsRegular() {
f, err = os.Open(*file)
if err != nil {
panic(err)
}
// Seek to record & block
if _, err := f.Seek(int64((*recordSize*blockSize**record)+*block*blockSize), 0); err != nil {
panic(err)
}
} else {
f, err = os.OpenFile(*file, os.O_RDONLY, os.ModeCharDevice)
if err != nil {
panic(err)
}
// Seek to record (we can't seek to block on tape)
// TODO: Seek to next header here too; currently this only works for the start of each archive/after a filemark
if err := seekToRecordOnTape(f, int32(*record)); err != nil {
panic(err)
}
}
defer f.Close()
var tr *tar.Reader
if fileDescription.Mode().IsRegular() {
tr = tar.NewReader(f)
} else {
br := bufio.NewReaderSize(f, blockSize**recordSize)
tr = tar.NewReader(br)
}
for {
hdr, err := tr.Next()
if err != nil {
panic(err)
}
log.Println(hdr)
currentRecord := int64(0)
if fileDescription.Mode().IsRegular() {
curr, err := f.Seek(0, io.SeekCurrent)
if err != nil {
panic(err)
}
currentRecord = ((curr + hdr.Size) / blockSize) / int64(*recordSize)
} else {
currentRecord, err = getCurrentRecordFromTape(f)
if err != nil {
panic(err)
}
}
if currentRecord > int64(*record) {
break
}
}
}
func seekToRecordOnTape(f *os.File, record int32) error {
if _, _, err := syscall.Syscall(
syscall.SYS_IOCTL,
f.Fd(),
MTIOCTOP,
uintptr(unsafe.Pointer(
&Operation{
Op: MTSEEK,
Count: record,
},
)),
); err != 0 {
return err
}
return nil
}
func getCurrentRecordFromTape(f *os.File) (int64, error) {
pos := &Position{}
if _, _, err := syscall.Syscall(
syscall.SYS_IOCTL,
f.Fd(),
MTIOCPOS,
uintptr(unsafe.Pointer(pos)),
); err != 0 {
return 0, err
}
return pos.BlkNo, nil
}

View File

@@ -122,7 +122,6 @@ func main() {
tr := tar.NewReader(br)
record := int64(0)
for {
hdr, err := tr.Next()
if err == io.EOF {
@@ -147,12 +146,22 @@ func main() {
panic(err)
}
log.Println("Record:", record, "Block:", 0, "Header:", hdr)
if record == 0 {
log.Println("Record:", 0, "Block:", 0, "Header:", hdr)
} else {
log.Println("Record:", record, "Block:", 0, "Header:", hdr)
}
record, err = getCurrentRecordFromTape(f)
curr, err := getCurrentRecordFromTape(f)
if err != nil {
panic(err)
}
if record == 0 {
record = ((curr * int64(*recordSize) * blockSize) + hdr.Size) / (int64(*recordSize) * blockSize) // For the first record of the file or archive, the offset of one is not needed
} else {
record = ((curr*int64(*recordSize)*blockSize)+hdr.Size)/(int64(*recordSize)*blockSize) + 2 // +2 because we need to start reading right after the last block
}
}
}
}