refactor: Use explicit reader/writer instead of filepath for drive

This commit is contained in:
Felicitas Pojtinger
2021-12-13 00:26:30 +01:00
parent 8ef3530b20
commit 6bd31d356c
34 changed files with 506 additions and 340 deletions

View File

@@ -12,6 +12,7 @@ import (
"github.com/pojntfx/stfs/pkg/config" "github.com/pojntfx/stfs/pkg/config"
"github.com/pojntfx/stfs/pkg/operations" "github.com/pojntfx/stfs/pkg/operations"
"github.com/pojntfx/stfs/pkg/recovery" "github.com/pojntfx/stfs/pkg/recovery"
"github.com/pojntfx/stfs/pkg/tape"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/viper" "github.com/spf13/viper"
) )
@@ -30,7 +31,7 @@ var archiveCmd = &cobra.Command{
Use: "archive", Use: "archive",
Aliases: []string{"arc", "a", "c"}, Aliases: []string{"arc", "a", "c"},
Short: "Archive a file or directory to tape or tar file", Short: "Archive a file or directory to tape or tar file",
PersistentPreRunE: func(cmd *cobra.Command, args []string) error { PreRunE: func(cmd *cobra.Command, args []string) error {
if err := viper.BindPFlags(cmd.PersistentFlags()); err != nil { if err := viper.BindPFlags(cmd.PersistentFlags()); err != nil {
return err return err
} }
@@ -83,10 +84,27 @@ var archiveCmd = &cobra.Command{
return err return err
} }
writer, writerIsRegular, err := tape.OpenTapeWriteOnly(
viper.GetString(driveFlag),
viper.GetInt(recordSizeFlag),
viper.GetBool(overwriteFlag),
)
if err != nil {
return nil
}
defer writer.Close()
reader, readerIsRegular, err := tape.OpenTapeReadOnly(
viper.GetString(driveFlag),
)
if err != nil {
return nil
}
defer reader.Close()
hdrs, err := operations.Archive( hdrs, err := operations.Archive(
config.StateConfig{ config.DriveWriterConfig{
Drive: viper.GetString(driveFlag), Drive: writer,
Metadata: viper.GetString(metadataFlag), DriveIsRegular: writerIsRegular,
}, },
config.PipeConfig{ config.PipeConfig{
Compression: viper.GetString(compressionFlag), Compression: viper.GetString(compressionFlag),
@@ -101,7 +119,6 @@ var archiveCmd = &cobra.Command{
viper.GetInt(recordSizeFlag), viper.GetInt(recordSizeFlag),
viper.GetString(fromFlag), viper.GetString(fromFlag),
viper.GetBool(overwriteFlag),
viper.GetString(compressionLevelFlag), viper.GetString(compressionLevelFlag),
logging.NewLogger().PrintHeader, logging.NewLogger().PrintHeader,
@@ -110,9 +127,21 @@ var archiveCmd = &cobra.Command{
return err return err
} }
index := 1 // Ignore the first header, which is the last header which we already indexed
if viper.GetBool(overwriteFlag) {
index = 0 // If we are starting fresh, index from start
}
return recovery.Index( return recovery.Index(
config.StateConfig{ config.DriveReaderConfig{
Drive: viper.GetString(driveFlag), Drive: reader,
DriveIsRegular: readerIsRegular,
},
config.DriveConfig{
Drive: reader,
DriveIsRegular: readerIsRegular,
},
config.MetadataConfig{
Metadata: viper.GetString(metadataFlag), Metadata: viper.GetString(metadataFlag),
}, },
config.PipeConfig{ config.PipeConfig{
@@ -130,7 +159,7 @@ var archiveCmd = &cobra.Command{
int(lastIndexedRecord), int(lastIndexedRecord),
int(lastIndexedBlock), int(lastIndexedBlock),
viper.GetBool(overwriteFlag), viper.GetBool(overwriteFlag),
1, // Ignore the first header, which is the last header which we already indexed index,
func(hdr *tar.Header, i int) error { func(hdr *tar.Header, i int) error {
if len(hdrs) <= i { if len(hdrs) <= i {

View File

@@ -5,6 +5,7 @@ import (
"github.com/pojntfx/stfs/internal/logging" "github.com/pojntfx/stfs/internal/logging"
"github.com/pojntfx/stfs/pkg/config" "github.com/pojntfx/stfs/pkg/config"
"github.com/pojntfx/stfs/pkg/operations" "github.com/pojntfx/stfs/pkg/operations"
"github.com/pojntfx/stfs/pkg/tape"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/viper" "github.com/spf13/viper"
) )
@@ -17,7 +18,7 @@ var deleteCmd = &cobra.Command{
Use: "delete", Use: "delete",
Aliases: []string{"del", "d", "rm"}, Aliases: []string{"del", "d", "rm"},
Short: "Delete a file or directory from tape or tar file", Short: "Delete a file or directory from tape or tar file",
PersistentPreRunE: func(cmd *cobra.Command, args []string) error { PreRunE: func(cmd *cobra.Command, args []string) error {
if err := viper.BindPFlags(cmd.PersistentFlags()); err != nil { if err := viper.BindPFlags(cmd.PersistentFlags()); err != nil {
return err return err
} }
@@ -49,9 +50,37 @@ var deleteCmd = &cobra.Command{
return err return err
} }
writer, writerIsRegular, err := tape.OpenTapeWriteOnly(
viper.GetString(driveFlag),
viper.GetInt(recordSizeFlag),
false,
)
if err != nil {
return nil
}
defer writer.Close()
reader, readerIsRegular, err := tape.OpenTapeReadOnly(
viper.GetString(driveFlag),
)
if err != nil {
return nil
}
defer reader.Close()
return operations.Delete( return operations.Delete(
config.StateConfig{ config.DriveWriterConfig{
Drive: viper.GetString(driveFlag), Drive: writer,
DriveIsRegular: writerIsRegular,
},
config.DriveReaderConfig{
Drive: reader,
DriveIsRegular: readerIsRegular,
},
config.DriveConfig{
Drive: reader,
DriveIsRegular: readerIsRegular,
},
config.MetadataConfig{
Metadata: viper.GetString(metadataFlag), Metadata: viper.GetString(metadataFlag),
}, },
config.PipeConfig{ config.PipeConfig{

View File

@@ -1,7 +1,9 @@
package cmd package cmd
import ( import (
"github.com/pojntfx/stfs/pkg/config"
"github.com/pojntfx/stfs/pkg/hardware" "github.com/pojntfx/stfs/pkg/hardware"
"github.com/pojntfx/stfs/pkg/tape"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/viper" "github.com/spf13/viper"
) )
@@ -14,9 +16,18 @@ var driveEjectCmd = &cobra.Command{
return err return err
} }
reader, readerIsRegular, err := tape.OpenTapeReadOnly(
viper.GetString(driveFlag),
)
if err != nil {
return nil
}
defer reader.Close()
return hardware.Eject( return hardware.Eject(
hardware.DriveConfig{ config.DriveConfig{
Drive: viper.GetString(driveFlag), Drive: reader,
DriveIsRegular: readerIsRegular,
}, },
) )
}, },

View File

@@ -3,7 +3,9 @@ package cmd
import ( import (
"fmt" "fmt"
"github.com/pojntfx/stfs/pkg/config"
"github.com/pojntfx/stfs/pkg/hardware" "github.com/pojntfx/stfs/pkg/hardware"
"github.com/pojntfx/stfs/pkg/tape"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/viper" "github.com/spf13/viper"
) )
@@ -16,9 +18,18 @@ var driveTellCmd = &cobra.Command{
return err return err
} }
reader, readerIsRegular, err := tape.OpenTapeReadOnly(
viper.GetString(driveFlag),
)
if err != nil {
return nil
}
defer reader.Close()
currentRecord, err := hardware.Tell( currentRecord, err := hardware.Tell(
hardware.DriveConfig{ config.DriveConfig{
Drive: viper.GetString(driveFlag), Drive: reader,
DriveIsRegular: readerIsRegular,
}, },
) )
if err != nil { if err != nil {

View File

@@ -2,6 +2,7 @@ package cmd
import ( import (
"github.com/pojntfx/stfs/internal/logging" "github.com/pojntfx/stfs/internal/logging"
"github.com/pojntfx/stfs/pkg/config"
"github.com/pojntfx/stfs/pkg/inventory" "github.com/pojntfx/stfs/pkg/inventory"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/viper" "github.com/spf13/viper"
@@ -21,7 +22,7 @@ var findCmd = &cobra.Command{
} }
if _, err := inventory.Find( if _, err := inventory.Find(
inventory.MetadataConfig{ config.MetadataConfig{
Metadata: viper.GetString(metadataFlag), Metadata: viper.GetString(metadataFlag),
}, },

View File

@@ -26,7 +26,7 @@ var keygenCmd = &cobra.Command{
Encryption: viper.GetString(encryptionFlag), Encryption: viper.GetString(encryptionFlag),
Signature: viper.GetString(signatureFlag), Signature: viper.GetString(signatureFlag),
}, },
utility.PasswordConfig{ config.PasswordConfig{
Password: viper.GetString(passwordFlag), Password: viper.GetString(passwordFlag),
}, },
) )

View File

@@ -2,6 +2,7 @@ package cmd
import ( import (
"github.com/pojntfx/stfs/internal/logging" "github.com/pojntfx/stfs/internal/logging"
"github.com/pojntfx/stfs/pkg/config"
"github.com/pojntfx/stfs/pkg/inventory" "github.com/pojntfx/stfs/pkg/inventory"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/viper" "github.com/spf13/viper"
@@ -17,7 +18,7 @@ var listCmd = &cobra.Command{
} }
if _, err := inventory.List( if _, err := inventory.List(
inventory.MetadataConfig{ config.MetadataConfig{
Metadata: viper.GetString(metadataFlag), Metadata: viper.GetString(metadataFlag),
}, },

View File

@@ -5,6 +5,7 @@ import (
"github.com/pojntfx/stfs/internal/logging" "github.com/pojntfx/stfs/internal/logging"
"github.com/pojntfx/stfs/pkg/config" "github.com/pojntfx/stfs/pkg/config"
"github.com/pojntfx/stfs/pkg/operations" "github.com/pojntfx/stfs/pkg/operations"
"github.com/pojntfx/stfs/pkg/tape"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/viper" "github.com/spf13/viper"
) )
@@ -13,7 +14,7 @@ var moveCmd = &cobra.Command{
Use: "move", Use: "move",
Aliases: []string{"mov", "m", "mv"}, Aliases: []string{"mov", "m", "mv"},
Short: "Move a file or directory on tape or tar file", Short: "Move a file or directory on tape or tar file",
PersistentPreRunE: func(cmd *cobra.Command, args []string) error { PreRunE: func(cmd *cobra.Command, args []string) error {
if err := viper.BindPFlags(cmd.PersistentFlags()); err != nil { if err := viper.BindPFlags(cmd.PersistentFlags()); err != nil {
return err return err
} }
@@ -45,9 +46,37 @@ var moveCmd = &cobra.Command{
return err return err
} }
writer, writerIsRegular, err := tape.OpenTapeWriteOnly(
viper.GetString(driveFlag),
viper.GetInt(recordSizeFlag),
false,
)
if err != nil {
return nil
}
defer writer.Close()
reader, readerIsRegular, err := tape.OpenTapeReadOnly(
viper.GetString(driveFlag),
)
if err != nil {
return nil
}
defer reader.Close()
return operations.Move( return operations.Move(
config.StateConfig{ config.DriveWriterConfig{
Drive: viper.GetString(driveFlag), Drive: writer,
DriveIsRegular: writerIsRegular,
},
config.DriveConfig{
Drive: reader,
DriveIsRegular: readerIsRegular,
},
config.DriveReaderConfig{
Drive: reader,
DriveIsRegular: readerIsRegular,
},
config.MetadataConfig{
Metadata: viper.GetString(metadataFlag), Metadata: viper.GetString(metadataFlag),
}, },
config.PipeConfig{ config.PipeConfig{

View File

@@ -4,8 +4,8 @@ import (
"github.com/pojntfx/stfs/internal/keys" "github.com/pojntfx/stfs/internal/keys"
"github.com/pojntfx/stfs/internal/logging" "github.com/pojntfx/stfs/internal/logging"
"github.com/pojntfx/stfs/pkg/config" "github.com/pojntfx/stfs/pkg/config"
"github.com/pojntfx/stfs/pkg/hardware"
"github.com/pojntfx/stfs/pkg/recovery" "github.com/pojntfx/stfs/pkg/recovery"
"github.com/pojntfx/stfs/pkg/tape"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/viper" "github.com/spf13/viper"
) )
@@ -20,7 +20,7 @@ const (
var recoveryFetchCmd = &cobra.Command{ var recoveryFetchCmd = &cobra.Command{
Use: "fetch", Use: "fetch",
Short: "Fetch a file or directory from tape or tar file by record and block without the index", Short: "Fetch a file or directory from tape or tar file by record and block without the index",
PersistentPreRunE: func(cmd *cobra.Command, args []string) error { PreRunE: func(cmd *cobra.Command, args []string) error {
if err := viper.BindPFlags(cmd.PersistentFlags()); err != nil { if err := viper.BindPFlags(cmd.PersistentFlags()); err != nil {
return err return err
} }
@@ -52,9 +52,22 @@ var recoveryFetchCmd = &cobra.Command{
return err return err
} }
reader, readerIsRegular, err := tape.OpenTapeReadOnly(
viper.GetString(driveFlag),
)
if err != nil {
return nil
}
defer reader.Close()
return recovery.Fetch( return recovery.Fetch(
hardware.DriveConfig{ config.DriveReaderConfig{
Drive: viper.GetString(driveFlag), Drive: reader,
DriveIsRegular: readerIsRegular,
},
config.DriveConfig{
Drive: reader,
DriveIsRegular: readerIsRegular,
}, },
config.PipeConfig{ config.PipeConfig{
Compression: viper.GetString(compressionFlag), Compression: viper.GetString(compressionFlag),

View File

@@ -9,6 +9,7 @@ import (
"github.com/pojntfx/stfs/internal/signature" "github.com/pojntfx/stfs/internal/signature"
"github.com/pojntfx/stfs/pkg/config" "github.com/pojntfx/stfs/pkg/config"
"github.com/pojntfx/stfs/pkg/recovery" "github.com/pojntfx/stfs/pkg/recovery"
"github.com/pojntfx/stfs/pkg/tape"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/viper" "github.com/spf13/viper"
) )
@@ -16,7 +17,7 @@ import (
var recoveryIndexCmd = &cobra.Command{ var recoveryIndexCmd = &cobra.Command{
Use: "index", Use: "index",
Short: "Index contents of tape or tar file", Short: "Index contents of tape or tar file",
PersistentPreRunE: func(cmd *cobra.Command, args []string) error { PreRunE: func(cmd *cobra.Command, args []string) error {
if err := viper.BindPFlags(cmd.PersistentFlags()); err != nil { if err := viper.BindPFlags(cmd.PersistentFlags()); err != nil {
return err return err
} }
@@ -48,9 +49,24 @@ var recoveryIndexCmd = &cobra.Command{
return err return err
} }
reader, readerIsRegular, err := tape.OpenTapeReadOnly(
viper.GetString(driveFlag),
)
if err != nil {
return nil
}
defer reader.Close()
return recovery.Index( return recovery.Index(
config.StateConfig{ config.DriveReaderConfig{
Drive: viper.GetString(driveFlag), Drive: reader,
DriveIsRegular: readerIsRegular,
},
config.DriveConfig{
Drive: reader,
DriveIsRegular: readerIsRegular,
},
config.MetadataConfig{
Metadata: viper.GetString(metadataFlag), Metadata: viper.GetString(metadataFlag),
}, },
config.PipeConfig{ config.PipeConfig{

View File

@@ -4,8 +4,8 @@ import (
"github.com/pojntfx/stfs/internal/keys" "github.com/pojntfx/stfs/internal/keys"
"github.com/pojntfx/stfs/internal/logging" "github.com/pojntfx/stfs/internal/logging"
"github.com/pojntfx/stfs/pkg/config" "github.com/pojntfx/stfs/pkg/config"
"github.com/pojntfx/stfs/pkg/hardware"
"github.com/pojntfx/stfs/pkg/recovery" "github.com/pojntfx/stfs/pkg/recovery"
"github.com/pojntfx/stfs/pkg/tape"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/viper" "github.com/spf13/viper"
) )
@@ -13,7 +13,7 @@ import (
var recoveryQueryCmd = &cobra.Command{ var recoveryQueryCmd = &cobra.Command{
Use: "query", Use: "query",
Short: "Query contents of tape or tar file without the index", Short: "Query contents of tape or tar file without the index",
PersistentPreRunE: func(cmd *cobra.Command, args []string) error { PreRunE: func(cmd *cobra.Command, args []string) error {
if err := viper.BindPFlags(cmd.PersistentFlags()); err != nil { if err := viper.BindPFlags(cmd.PersistentFlags()); err != nil {
return err return err
} }
@@ -45,9 +45,18 @@ var recoveryQueryCmd = &cobra.Command{
return err return err
} }
reader, readerIsRegular, err := tape.OpenTapeReadOnly(
viper.GetString(driveFlag),
)
if err != nil {
return nil
}
defer reader.Close()
if _, err := recovery.Query( if _, err := recovery.Query(
hardware.DriveConfig{ config.DriveConfig{
Drive: viper.GetString(driveFlag), Drive: reader,
DriveIsRegular: readerIsRegular,
}, },
config.PipeConfig{ config.PipeConfig{
Compression: viper.GetString(compressionFlag), Compression: viper.GetString(compressionFlag),

View File

@@ -5,6 +5,7 @@ import (
"github.com/pojntfx/stfs/internal/logging" "github.com/pojntfx/stfs/internal/logging"
"github.com/pojntfx/stfs/pkg/config" "github.com/pojntfx/stfs/pkg/config"
"github.com/pojntfx/stfs/pkg/operations" "github.com/pojntfx/stfs/pkg/operations"
"github.com/pojntfx/stfs/pkg/tape"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/viper" "github.com/spf13/viper"
) )
@@ -17,7 +18,7 @@ var restoreCmd = &cobra.Command{
Use: "restore", Use: "restore",
Aliases: []string{"res", "r", "x"}, Aliases: []string{"res", "r", "x"},
Short: "Restore a file or directory from tape or tar file", Short: "Restore a file or directory from tape or tar file",
PersistentPreRunE: func(cmd *cobra.Command, args []string) error { PreRunE: func(cmd *cobra.Command, args []string) error {
if err := viper.BindPFlags(cmd.PersistentFlags()); err != nil { if err := viper.BindPFlags(cmd.PersistentFlags()); err != nil {
return err return err
} }
@@ -49,9 +50,24 @@ var restoreCmd = &cobra.Command{
return err return err
} }
reader, readerIsRegular, err := tape.OpenTapeReadOnly(
viper.GetString(driveFlag),
)
if err != nil {
return nil
}
defer reader.Close()
return operations.Restore( return operations.Restore(
config.StateConfig{ config.DriveReaderConfig{
Drive: viper.GetString(driveFlag), Drive: reader,
DriveIsRegular: readerIsRegular,
},
config.DriveConfig{
Drive: reader,
DriveIsRegular: readerIsRegular,
},
config.MetadataConfig{
Metadata: viper.GetString(metadataFlag), Metadata: viper.GetString(metadataFlag),
}, },
config.PipeConfig{ config.PipeConfig{

View File

@@ -12,6 +12,7 @@ import (
"github.com/pojntfx/stfs/pkg/config" "github.com/pojntfx/stfs/pkg/config"
"github.com/pojntfx/stfs/pkg/operations" "github.com/pojntfx/stfs/pkg/operations"
"github.com/pojntfx/stfs/pkg/recovery" "github.com/pojntfx/stfs/pkg/recovery"
"github.com/pojntfx/stfs/pkg/tape"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/viper" "github.com/spf13/viper"
) )
@@ -20,7 +21,7 @@ var updateCmd = &cobra.Command{
Use: "update", Use: "update",
Aliases: []string{"upd", "u"}, Aliases: []string{"upd", "u"},
Short: "Update a file or directory's content and metadata on tape or tar file", Short: "Update a file or directory's content and metadata on tape or tar file",
PersistentPreRunE: func(cmd *cobra.Command, args []string) error { PreRunE: func(cmd *cobra.Command, args []string) error {
if err := viper.BindPFlags(cmd.PersistentFlags()); err != nil { if err := viper.BindPFlags(cmd.PersistentFlags()); err != nil {
return err return err
} }
@@ -66,10 +67,27 @@ var updateCmd = &cobra.Command{
return err return err
} }
writer, writerIsRegular, err := tape.OpenTapeWriteOnly(
viper.GetString(driveFlag),
viper.GetInt(recordSizeFlag),
false,
)
if err != nil {
return nil
}
defer writer.Close()
reader, readerIsRegular, err := tape.OpenTapeReadOnly(
viper.GetString(driveFlag),
)
if err != nil {
return nil
}
defer reader.Close()
hdrs, err := operations.Update( hdrs, err := operations.Update(
config.StateConfig{ config.DriveWriterConfig{
Drive: viper.GetString(driveFlag), Drive: writer,
Metadata: viper.GetString(metadataFlag), DriveIsRegular: writerIsRegular,
}, },
config.PipeConfig{ config.PipeConfig{
Compression: viper.GetString(compressionFlag), Compression: viper.GetString(compressionFlag),
@@ -94,8 +112,15 @@ var updateCmd = &cobra.Command{
} }
return recovery.Index( return recovery.Index(
config.StateConfig{ config.DriveReaderConfig{
Drive: viper.GetString(driveFlag), Drive: reader,
DriveIsRegular: readerIsRegular,
},
config.DriveConfig{
Drive: reader,
DriveIsRegular: readerIsRegular,
},
config.MetadataConfig{
Metadata: viper.GetString(metadataFlag), Metadata: viper.GetString(metadataFlag),
}, },
config.PipeConfig{ config.PipeConfig{

View File

@@ -1,79 +0,0 @@
package tape
import (
"archive/tar"
"bufio"
"os"
"github.com/pojntfx/stfs/internal/ioext"
"github.com/pojntfx/stfs/internal/mtio"
)
func OpenTapeWriteOnly(drive string, recordSize int, overwrite bool) (tw *tar.Writer, isRegular bool, cleanup func(dirty *bool) error, err error) {
stat, err := os.Stat(drive)
if err == nil {
isRegular = stat.Mode().IsRegular()
} else {
if os.IsNotExist(err) {
isRegular = true
} else {
return nil, false, nil, err
}
}
var f *os.File
if isRegular {
f, err = os.OpenFile(drive, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
if err != nil {
return nil, false, nil, err
}
// No need to go to end manually due to `os.O_APPEND`
} else {
f, err = os.OpenFile(drive, os.O_APPEND|os.O_WRONLY, os.ModeCharDevice)
if err != nil {
return nil, false, nil, err
}
if !overwrite {
// Go to end of tape
if err := mtio.GoToEndOfTape(f); err != nil {
return nil, false, nil, err
}
}
}
var bw *bufio.Writer
var counter *ioext.CounterWriter
if isRegular {
tw = tar.NewWriter(f)
} else {
bw = bufio.NewWriterSize(f, mtio.BlockSize*recordSize)
counter = &ioext.CounterWriter{Writer: bw, BytesRead: 0}
tw = tar.NewWriter(counter)
}
return tw, isRegular, func(dirty *bool) error {
// Only write the trailer if we wrote to the archive
if *dirty {
if err := tw.Close(); err != nil {
return err
}
if !isRegular {
if mtio.BlockSize*recordSize-counter.BytesRead > 0 {
// Fill the rest of the record with zeros
if _, err := bw.Write(make([]byte, mtio.BlockSize*recordSize-counter.BytesRead)); err != nil {
return err
}
}
if err := bw.Flush(); err != nil {
return err
}
}
}
return f.Close()
}, nil
}

46
internal/tarext/write.go Normal file
View File

@@ -0,0 +1,46 @@
package tarext
import (
"archive/tar"
"bufio"
"io"
"github.com/pojntfx/stfs/internal/ioext"
"github.com/pojntfx/stfs/internal/mtio"
)
func NewTapeWriter(f io.Writer, isRegular bool, recordSize int) (tw *tar.Writer, cleanup func(dirty *bool) error, err error) {
var bw *bufio.Writer
var counter *ioext.CounterWriter
if isRegular {
tw = tar.NewWriter(f)
} else {
bw = bufio.NewWriterSize(f, mtio.BlockSize*recordSize)
counter = &ioext.CounterWriter{Writer: bw, BytesRead: 0}
tw = tar.NewWriter(counter)
}
return tw, func(dirty *bool) error {
// Only write the trailer if we wrote to the archive
if *dirty {
if err := tw.Close(); err != nil {
return err
}
if !isRegular {
if mtio.BlockSize*recordSize-counter.BytesRead > 0 {
// Fill the rest of the record with zeros
if _, err := bw.Write(make([]byte, mtio.BlockSize*recordSize-counter.BytesRead)); err != nil {
return err
}
}
if err := bw.Flush(); err != nil {
return err
}
}
}
return nil
}, nil
}

View File

@@ -1,7 +1,26 @@
package config package config
type StateConfig struct { import (
Drive string "io"
"os"
)
type DriveReaderConfig struct {
Drive io.ReadSeeker
DriveIsRegular bool
}
type DriveWriterConfig struct {
Drive io.Writer
DriveIsRegular bool
}
type DriveConfig struct {
Drive *os.File
DriveIsRegular bool
}
type MetadataConfig struct {
Metadata string Metadata string
} }
@@ -16,3 +35,7 @@ type CryptoConfig struct {
Identity interface{} Identity interface{}
Password string Password string
} }
type PasswordConfig struct {
Password string
}

View File

@@ -1,5 +0,0 @@
package hardware
type DriveConfig struct {
Drive string
}

View File

@@ -1,19 +1,12 @@
package hardware package hardware
import ( import (
"os"
"github.com/pojntfx/stfs/internal/mtio" "github.com/pojntfx/stfs/internal/mtio"
"github.com/pojntfx/stfs/pkg/config"
) )
func Eject( func Eject(
state DriveConfig, state config.DriveConfig,
) error { ) error {
f, err := os.OpenFile(state.Drive, os.O_RDONLY, os.ModeCharDevice) return mtio.EjectTape(state.Drive)
if err != nil {
return err
}
defer f.Close()
return mtio.EjectTape(f)
} }

View File

@@ -1,19 +1,12 @@
package hardware package hardware
import ( import (
"os"
"github.com/pojntfx/stfs/internal/mtio" "github.com/pojntfx/stfs/internal/mtio"
"github.com/pojntfx/stfs/pkg/config"
) )
func Tell( func Tell(
state DriveConfig, state config.DriveConfig,
) (int64, error) { ) (int64, error) {
f, err := os.OpenFile(state.Drive, os.O_RDONLY, os.ModeCharDevice) return mtio.GetCurrentRecordFromTape(state.Drive)
if err != nil {
return -1, err
}
defer f.Close()
return mtio.GetCurrentRecordFromTape(f)
} }

View File

@@ -1,5 +0,0 @@
package inventory
type MetadataConfig struct {
Metadata string
}

View File

@@ -8,10 +8,11 @@ import (
"github.com/pojntfx/stfs/internal/converters" "github.com/pojntfx/stfs/internal/converters"
models "github.com/pojntfx/stfs/internal/db/sqlite/models/metadata" models "github.com/pojntfx/stfs/internal/db/sqlite/models/metadata"
"github.com/pojntfx/stfs/internal/persisters" "github.com/pojntfx/stfs/internal/persisters"
"github.com/pojntfx/stfs/pkg/config"
) )
func Find( func Find(
state MetadataConfig, state config.MetadataConfig,
expression string, expression string,

View File

@@ -7,10 +7,11 @@ import (
"github.com/pojntfx/stfs/internal/converters" "github.com/pojntfx/stfs/internal/converters"
models "github.com/pojntfx/stfs/internal/db/sqlite/models/metadata" models "github.com/pojntfx/stfs/internal/db/sqlite/models/metadata"
"github.com/pojntfx/stfs/internal/persisters" "github.com/pojntfx/stfs/internal/persisters"
"github.com/pojntfx/stfs/pkg/config"
) )
func List( func List(
state MetadataConfig, state config.MetadataConfig,
name string, name string,

View File

@@ -20,7 +20,7 @@ import (
"github.com/pojntfx/stfs/internal/signature" "github.com/pojntfx/stfs/internal/signature"
"github.com/pojntfx/stfs/internal/statext" "github.com/pojntfx/stfs/internal/statext"
"github.com/pojntfx/stfs/internal/suffix" "github.com/pojntfx/stfs/internal/suffix"
"github.com/pojntfx/stfs/internal/tape" "github.com/pojntfx/stfs/internal/tarext"
"github.com/pojntfx/stfs/pkg/config" "github.com/pojntfx/stfs/pkg/config"
) )
@@ -29,73 +29,21 @@ var (
) )
func Archive( func Archive(
state config.StateConfig, writer config.DriveWriterConfig,
pipes config.PipeConfig, pipes config.PipeConfig,
crypto config.CryptoConfig, crypto config.CryptoConfig,
recordSize int, recordSize int,
from string, from string,
overwrite bool,
compressionLevel string, compressionLevel string,
onHeader func(hdr *models.Header), onHeader func(hdr *models.Header),
) ([]*tar.Header, error) { ) ([]*tar.Header, error) {
dirty := false dirty := false
tw, isRegular, cleanup, err := tape.OpenTapeWriteOnly(state.Drive, recordSize, overwrite) tw, cleanup, err := tarext.NewTapeWriter(writer.Drive, writer.DriveIsRegular, recordSize)
if err != nil { if err != nil {
return []*tar.Header{}, err return []*tar.Header{}, err
} }
if overwrite {
if isRegular {
if err := cleanup(&dirty); err != nil { // dirty will always be false here
return []*tar.Header{}, err
}
f, err := os.OpenFile(state.Drive, os.O_WRONLY|os.O_CREATE, 0600)
if err != nil {
return []*tar.Header{}, err
}
// Clear the file's content
if err := f.Truncate(0); err != nil {
return []*tar.Header{}, err
}
if err := f.Close(); err != nil {
return []*tar.Header{}, err
}
tw, isRegular, cleanup, err = tape.OpenTapeWriteOnly(state.Drive, recordSize, overwrite)
if err != nil {
return []*tar.Header{}, err
}
} else {
if err := cleanup(&dirty); err != nil { // dirty will always be false here
return []*tar.Header{}, err
}
f, err := os.OpenFile(state.Drive, os.O_WRONLY, os.ModeCharDevice)
if err != nil {
return []*tar.Header{}, err
}
// Seek to the start of the tape
if err := mtio.SeekToRecordOnTape(f, 0); err != nil {
return []*tar.Header{}, err
}
if err := f.Close(); err != nil {
return []*tar.Header{}, err
}
tw, isRegular, cleanup, err = tape.OpenTapeWriteOnly(state.Drive, recordSize, overwrite)
if err != nil {
return []*tar.Header{}, err
}
}
}
defer cleanup(&dirty) defer cleanup(&dirty)
headers := []*tar.Header{} headers := []*tar.Header{}
@@ -143,7 +91,7 @@ func Archive(
encryptor, encryptor,
pipes.Compression, pipes.Compression,
compressionLevel, compressionLevel,
isRegular, writer.DriveIsRegular,
recordSize, recordSize,
) )
if err != nil { if err != nil {
@@ -155,12 +103,12 @@ func Archive(
return err return err
} }
signer, sign, err := signature.Sign(file, isRegular, pipes.Signature, crypto.Identity) signer, sign, err := signature.Sign(file, writer.DriveIsRegular, pipes.Signature, crypto.Identity)
if err != nil { if err != nil {
return err return err
} }
if isRegular { if writer.DriveIsRegular {
if _, err := io.Copy(compressor, signer); err != nil { if _, err := io.Copy(compressor, signer); err != nil {
return err return err
} }
@@ -219,7 +167,7 @@ func Archive(
hdrToAppend := *hdr hdrToAppend := *hdr
headers = append(headers, &hdrToAppend) headers = append(headers, &hdrToAppend)
if err := signature.SignHeader(hdr, isRegular, pipes.Signature, crypto.Identity); err != nil { if err := signature.SignHeader(hdr, writer.DriveIsRegular, pipes.Signature, crypto.Identity); err != nil {
return err return err
} }
@@ -247,7 +195,7 @@ func Archive(
encryptor, encryptor,
pipes.Compression, pipes.Compression,
compressionLevel, compressionLevel,
isRegular, writer.DriveIsRegular,
recordSize, recordSize,
) )
if err != nil { if err != nil {
@@ -259,7 +207,7 @@ func Archive(
return err return err
} }
if isRegular { if writer.DriveIsRegular {
if _, err := io.Copy(compressor, file); err != nil { if _, err := io.Copy(compressor, file); err != nil {
return err return err
} }

View File

@@ -10,13 +10,16 @@ import (
"github.com/pojntfx/stfs/internal/persisters" "github.com/pojntfx/stfs/internal/persisters"
"github.com/pojntfx/stfs/internal/records" "github.com/pojntfx/stfs/internal/records"
"github.com/pojntfx/stfs/internal/signature" "github.com/pojntfx/stfs/internal/signature"
"github.com/pojntfx/stfs/internal/tape" "github.com/pojntfx/stfs/internal/tarext"
"github.com/pojntfx/stfs/pkg/config" "github.com/pojntfx/stfs/pkg/config"
"github.com/pojntfx/stfs/pkg/recovery" "github.com/pojntfx/stfs/pkg/recovery"
) )
func Delete( func Delete(
state config.StateConfig, writer config.DriveWriterConfig,
reader config.DriveReaderConfig,
drive config.DriveConfig,
metadata config.MetadataConfig,
pipes config.PipeConfig, pipes config.PipeConfig,
crypto config.CryptoConfig, crypto config.CryptoConfig,
@@ -26,13 +29,13 @@ func Delete(
onHeader func(hdr *models.Header), onHeader func(hdr *models.Header),
) error { ) error {
dirty := false dirty := false
tw, isRegular, cleanup, err := tape.OpenTapeWriteOnly(state.Drive, recordSize, false) tw, cleanup, err := tarext.NewTapeWriter(writer.Drive, writer.DriveIsRegular, recordSize)
if err != nil { if err != nil {
return err return err
} }
defer cleanup(&dirty) defer cleanup(&dirty)
metadataPersister := persisters.NewMetadataPersister(state.Metadata) metadataPersister := persisters.NewMetadataPersister(metadata.Metadata)
if err := metadataPersister.Open(); err != nil { if err := metadataPersister.Open(); err != nil {
return err return err
} }
@@ -60,7 +63,7 @@ func Delete(
} }
// Append deletion hdrs to the tape or tar file // Append deletion hdrs to the tape or tar file
hdrs := []*tar.Header{} hdrs := []tar.Header{}
for _, dbhdr := range headersToDelete { for _, dbhdr := range headersToDelete {
hdr, err := converters.DBHeaderToTarHeader(dbhdr) hdr, err := converters.DBHeaderToTarHeader(dbhdr)
if err != nil { if err != nil {
@@ -71,7 +74,18 @@ func Delete(
hdr.PAXRecords[records.STFSRecordVersion] = records.STFSRecordVersion1 hdr.PAXRecords[records.STFSRecordVersion] = records.STFSRecordVersion1
hdr.PAXRecords[records.STFSRecordAction] = records.STFSRecordActionDelete hdr.PAXRecords[records.STFSRecordAction] = records.STFSRecordActionDelete
if err := signature.SignHeader(hdr, isRegular, pipes.Signature, crypto.Identity); err != nil { hdrs = append(hdrs, *hdr)
if onHeader != nil {
dbhdr, err := converters.TarHeaderToDBHeader(-1, -1, -1, -1, hdr)
if err != nil {
return err
}
onHeader(dbhdr)
}
if err := signature.SignHeader(hdr, writer.DriveIsRegular, pipes.Signature, crypto.Identity); err != nil {
return err return err
} }
@@ -84,21 +98,12 @@ func Delete(
} }
dirty = true dirty = true
if onHeader != nil {
dbhdr, err := converters.TarHeaderToDBHeader(-1, -1, -1, -1, hdr)
if err != nil {
return err
}
onHeader(dbhdr)
}
hdrs = append(hdrs, hdr)
} }
return recovery.Index( return recovery.Index(
state, reader,
drive,
metadata,
pipes, pipes,
crypto, crypto,
@@ -113,7 +118,7 @@ func Delete(
return config.ErrTarHeaderMissing return config.ErrTarHeaderMissing
} }
*hdr = *hdrs[i] *hdr = hdrs[i]
return nil return nil
}, },

View File

@@ -11,13 +11,16 @@ import (
"github.com/pojntfx/stfs/internal/persisters" "github.com/pojntfx/stfs/internal/persisters"
"github.com/pojntfx/stfs/internal/records" "github.com/pojntfx/stfs/internal/records"
"github.com/pojntfx/stfs/internal/signature" "github.com/pojntfx/stfs/internal/signature"
"github.com/pojntfx/stfs/internal/tape" "github.com/pojntfx/stfs/internal/tarext"
"github.com/pojntfx/stfs/pkg/config" "github.com/pojntfx/stfs/pkg/config"
"github.com/pojntfx/stfs/pkg/recovery" "github.com/pojntfx/stfs/pkg/recovery"
) )
func Move( func Move(
state config.StateConfig, writer config.DriveWriterConfig,
drive config.DriveConfig,
reader config.DriveReaderConfig,
metadata config.MetadataConfig,
pipes config.PipeConfig, pipes config.PipeConfig,
crypto config.CryptoConfig, crypto config.CryptoConfig,
@@ -28,13 +31,13 @@ func Move(
onHeader func(hdr *models.Header), onHeader func(hdr *models.Header),
) error { ) error {
dirty := false dirty := false
tw, isRegular, cleanup, err := tape.OpenTapeWriteOnly(state.Drive, recordSize, false) tw, cleanup, err := tarext.NewTapeWriter(writer.Drive, writer.DriveIsRegular, recordSize)
if err != nil { if err != nil {
return err return err
} }
defer cleanup(&dirty) defer cleanup(&dirty)
metadataPersister := persisters.NewMetadataPersister(state.Metadata) metadataPersister := persisters.NewMetadataPersister(metadata.Metadata)
if err := metadataPersister.Open(); err != nil { if err := metadataPersister.Open(); err != nil {
return err return err
} }
@@ -62,7 +65,7 @@ func Move(
} }
// Append move headers to the tape or tar file // Append move headers to the tape or tar file
hdrs := []*tar.Header{} hdrs := []tar.Header{}
for _, dbhdr := range headersToMove { for _, dbhdr := range headersToMove {
hdr, err := converters.DBHeaderToTarHeader(dbhdr) hdr, err := converters.DBHeaderToTarHeader(dbhdr)
if err != nil { if err != nil {
@@ -75,7 +78,18 @@ func Move(
hdr.PAXRecords[records.STFSRecordAction] = records.STFSRecordActionUpdate hdr.PAXRecords[records.STFSRecordAction] = records.STFSRecordActionUpdate
hdr.PAXRecords[records.STFSRecordReplacesName] = dbhdr.Name hdr.PAXRecords[records.STFSRecordReplacesName] = dbhdr.Name
if err := signature.SignHeader(hdr, isRegular, pipes.Signature, crypto.Identity); err != nil { hdrs = append(hdrs, *hdr)
if onHeader != nil {
dbhdr, err := converters.TarHeaderToDBHeader(-1, -1, -1, -1, hdr)
if err != nil {
return err
}
onHeader(dbhdr)
}
if err := signature.SignHeader(hdr, writer.DriveIsRegular, pipes.Signature, crypto.Identity); err != nil {
return err return err
} }
@@ -88,21 +102,12 @@ func Move(
} }
dirty = true dirty = true
if onHeader != nil {
dbhdr, err := converters.TarHeaderToDBHeader(-1, -1, -1, -1, hdr)
if err != nil {
return err
}
onHeader(dbhdr)
}
hdrs = append(hdrs, hdr)
} }
return recovery.Index( return recovery.Index(
state, reader,
drive,
metadata,
pipes, pipes,
crypto, crypto,
@@ -117,7 +122,7 @@ func Move(
return config.ErrTarHeaderMissing return config.ErrTarHeaderMissing
} }
*hdr = *hdrs[i] *hdr = hdrs[i]
return nil return nil
}, },

View File

@@ -11,12 +11,13 @@ import (
models "github.com/pojntfx/stfs/internal/db/sqlite/models/metadata" models "github.com/pojntfx/stfs/internal/db/sqlite/models/metadata"
"github.com/pojntfx/stfs/internal/persisters" "github.com/pojntfx/stfs/internal/persisters"
"github.com/pojntfx/stfs/pkg/config" "github.com/pojntfx/stfs/pkg/config"
"github.com/pojntfx/stfs/pkg/hardware"
"github.com/pojntfx/stfs/pkg/recovery" "github.com/pojntfx/stfs/pkg/recovery"
) )
func Restore( func Restore(
state config.StateConfig, reader config.DriveReaderConfig,
drive config.DriveConfig,
metadata config.MetadataConfig,
pipes config.PipeConfig, pipes config.PipeConfig,
crypto config.CryptoConfig, crypto config.CryptoConfig,
@@ -27,7 +28,7 @@ func Restore(
onHeader func(hdr *models.Header), onHeader func(hdr *models.Header),
) error { ) error {
metadataPersister := persisters.NewMetadataPersister(state.Metadata) metadataPersister := persisters.NewMetadataPersister(metadata.Metadata)
if err := metadataPersister.Open(); err != nil { if err := metadataPersister.Open(); err != nil {
return err return err
} }
@@ -78,9 +79,8 @@ func Restore(
} }
if err := recovery.Fetch( if err := recovery.Fetch(
hardware.DriveConfig{ reader,
Drive: state.Drive, drive,
},
pipes, pipes,
crypto, crypto,

View File

@@ -18,12 +18,12 @@ import (
"github.com/pojntfx/stfs/internal/signature" "github.com/pojntfx/stfs/internal/signature"
"github.com/pojntfx/stfs/internal/statext" "github.com/pojntfx/stfs/internal/statext"
"github.com/pojntfx/stfs/internal/suffix" "github.com/pojntfx/stfs/internal/suffix"
"github.com/pojntfx/stfs/internal/tape" "github.com/pojntfx/stfs/internal/tarext"
"github.com/pojntfx/stfs/pkg/config" "github.com/pojntfx/stfs/pkg/config"
) )
func Update( func Update(
state config.StateConfig, writer config.DriveWriterConfig,
pipes config.PipeConfig, pipes config.PipeConfig,
crypto config.CryptoConfig, crypto config.CryptoConfig,
@@ -35,7 +35,7 @@ func Update(
onHeader func(hdr *models.Header), onHeader func(hdr *models.Header),
) ([]*tar.Header, error) { ) ([]*tar.Header, error) {
dirty := false dirty := false
tw, isRegular, cleanup, err := tape.OpenTapeWriteOnly(state.Drive, recordSize, false) tw, cleanup, err := tarext.NewTapeWriter(writer.Drive, writer.DriveIsRegular, recordSize)
if err != nil { if err != nil {
return []*tar.Header{}, err return []*tar.Header{}, err
} }
@@ -86,7 +86,7 @@ func Update(
encryptor, encryptor,
pipes.Compression, pipes.Compression,
compressionLevel, compressionLevel,
isRegular, writer.DriveIsRegular,
recordSize, recordSize,
) )
if err != nil { if err != nil {
@@ -98,12 +98,12 @@ func Update(
return err return err
} }
signer, sign, err := signature.Sign(file, isRegular, pipes.Signature, crypto.Identity) signer, sign, err := signature.Sign(file, writer.DriveIsRegular, pipes.Signature, crypto.Identity)
if err != nil { if err != nil {
return err return err
} }
if isRegular { if writer.DriveIsRegular {
if _, err := io.Copy(compressor, signer); err != nil { if _, err := io.Copy(compressor, signer); err != nil {
return err return err
} }
@@ -165,7 +165,7 @@ func Update(
hdrToAppend := *hdr hdrToAppend := *hdr
headers = append(headers, &hdrToAppend) headers = append(headers, &hdrToAppend)
if err := signature.SignHeader(hdr, isRegular, pipes.Signature, crypto.Identity); err != nil { if err := signature.SignHeader(hdr, writer.DriveIsRegular, pipes.Signature, crypto.Identity); err != nil {
return err return err
} }
@@ -191,7 +191,7 @@ func Update(
encryptor, encryptor,
pipes.Compression, pipes.Compression,
compressionLevel, compressionLevel,
isRegular, writer.DriveIsRegular,
recordSize, recordSize,
) )
if err != nil { if err != nil {
@@ -203,7 +203,7 @@ func Update(
return err return err
} }
if isRegular { if writer.DriveIsRegular {
if _, err := io.Copy(compressor, file); err != nil { if _, err := io.Copy(compressor, file); err != nil {
return err return err
} }
@@ -244,7 +244,7 @@ func Update(
hdrToAppend := *hdr hdrToAppend := *hdr
headers = append(headers, &hdrToAppend) headers = append(headers, &hdrToAppend)
if err := signature.SignHeader(hdr, isRegular, pipes.Signature, crypto.Identity); err != nil { if err := signature.SignHeader(hdr, writer.DriveIsRegular, pipes.Signature, crypto.Identity); err != nil {
return err return err
} }

View File

@@ -14,13 +14,12 @@ import (
"github.com/pojntfx/stfs/internal/mtio" "github.com/pojntfx/stfs/internal/mtio"
"github.com/pojntfx/stfs/internal/records" "github.com/pojntfx/stfs/internal/records"
"github.com/pojntfx/stfs/internal/signature" "github.com/pojntfx/stfs/internal/signature"
"github.com/pojntfx/stfs/internal/tape"
"github.com/pojntfx/stfs/pkg/config" "github.com/pojntfx/stfs/pkg/config"
"github.com/pojntfx/stfs/pkg/hardware"
) )
func Fetch( func Fetch(
state hardware.DriveConfig, reader config.DriveReaderConfig,
drive config.DriveConfig,
pipes config.PipeConfig, pipes config.PipeConfig,
crypto config.CryptoConfig, crypto config.CryptoConfig,
@@ -32,28 +31,22 @@ func Fetch(
onHeader func(hdr *models.Header), onHeader func(hdr *models.Header),
) error { ) error {
f, isRegular, err := tape.OpenTapeReadOnly(state.Drive)
if err != nil {
return err
}
defer f.Close()
var tr *tar.Reader var tr *tar.Reader
if isRegular { if reader.DriveIsRegular {
// Seek to record and block // Seek to record and block
if _, err := f.Seek(int64((recordSize*mtio.BlockSize*record)+block*mtio.BlockSize), io.SeekStart); err != nil { if _, err := reader.Drive.Seek(int64((recordSize*mtio.BlockSize*record)+block*mtio.BlockSize), io.SeekStart); err != nil {
return err return err
} }
tr = tar.NewReader(f) tr = tar.NewReader(reader.Drive)
} else { } else {
// Seek to record // Seek to record
if err := mtio.SeekToRecordOnTape(f, int32(record)); err != nil { if err := mtio.SeekToRecordOnTape(drive.Drive, int32(record)); err != nil {
return err return err
} }
// Seek to block // Seek to block
br := bufio.NewReaderSize(f, mtio.BlockSize*recordSize) br := bufio.NewReaderSize(drive.Drive, mtio.BlockSize*recordSize)
if _, err := br.Read(make([]byte, block*mtio.BlockSize)); err != nil { if _, err := br.Read(make([]byte, block*mtio.BlockSize)); err != nil {
return err return err
} }
@@ -70,7 +63,7 @@ func Fetch(
return err return err
} }
if err := signature.VerifyHeader(hdr, isRegular, pipes.Signature, crypto.Recipient); err != nil { if err := signature.VerifyHeader(hdr, drive.DriveIsRegular, pipes.Signature, crypto.Recipient); err != nil {
return err return err
} }
@@ -127,7 +120,7 @@ func Fetch(
} }
} }
verifier, verify, err := signature.Verify(decompressor, isRegular, pipes.Signature, crypto.Recipient, sig) verifier, verify, err := signature.Verify(decompressor, drive.DriveIsRegular, pipes.Signature, crypto.Recipient, sig)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -18,12 +18,13 @@ import (
"github.com/pojntfx/stfs/internal/persisters" "github.com/pojntfx/stfs/internal/persisters"
"github.com/pojntfx/stfs/internal/records" "github.com/pojntfx/stfs/internal/records"
"github.com/pojntfx/stfs/internal/suffix" "github.com/pojntfx/stfs/internal/suffix"
"github.com/pojntfx/stfs/internal/tape"
"github.com/pojntfx/stfs/pkg/config" "github.com/pojntfx/stfs/pkg/config"
) )
func Index( func Index(
state config.StateConfig, reader config.DriveReaderConfig,
drive config.DriveConfig,
metadata config.MetadataConfig,
pipes config.PipeConfig, pipes config.PipeConfig,
crypto config.CryptoConfig, crypto config.CryptoConfig,
@@ -45,7 +46,7 @@ func Index(
onHeader func(hdr *models.Header), onHeader func(hdr *models.Header),
) error { ) error {
if overwrite { if overwrite {
f, err := os.OpenFile(state.Metadata, os.O_WRONLY|os.O_CREATE, 0600) f, err := os.OpenFile(metadata.Metadata, os.O_WRONLY|os.O_CREATE, 0600)
if err != nil { if err != nil {
return err return err
} }
@@ -59,24 +60,18 @@ func Index(
} }
} }
metadataPersister := persisters.NewMetadataPersister(state.Metadata) metadataPersister := persisters.NewMetadataPersister(metadata.Metadata)
if err := metadataPersister.Open(); err != nil { if err := metadataPersister.Open(); err != nil {
return err return err
} }
f, isRegular, err := tape.OpenTapeReadOnly(state.Drive) if reader.DriveIsRegular {
if err != nil {
return err
}
defer f.Close()
if isRegular {
// Seek to record and block // Seek to record and block
if _, err := f.Seek(int64((recordSize*mtio.BlockSize*record)+block*mtio.BlockSize), 0); err != nil { if _, err := reader.Drive.Seek(int64((recordSize*mtio.BlockSize*record)+block*mtio.BlockSize), 0); err != nil {
return err return err
} }
tr := tar.NewReader(f) tr := tar.NewReader(reader.Drive)
record := int64(record) record := int64(record)
block := int64(block) block := int64(block)
@@ -86,7 +81,7 @@ func Index(
hdr, err := tr.Next() hdr, err := tr.Next()
if err != nil { if err != nil {
for { for {
curr, err := f.Seek(0, io.SeekCurrent) curr, err := reader.Drive.Seek(0, io.SeekCurrent)
if err != nil { if err != nil {
return err return err
} }
@@ -104,11 +99,11 @@ func Index(
} }
// Seek to record and block // Seek to record and block
if _, err := f.Seek(int64((recordSize*mtio.BlockSize*int(record))+int(block)*mtio.BlockSize), io.SeekStart); err != nil { if _, err := reader.Drive.Seek(int64((recordSize*mtio.BlockSize*int(record))+int(block)*mtio.BlockSize), io.SeekStart); err != nil {
return err return err
} }
tr = tar.NewReader(f) tr = tar.NewReader(reader.Drive)
hdr, err = tr.Next() hdr, err = tr.Next()
if err != nil { if err != nil {
@@ -135,7 +130,7 @@ func Index(
return err return err
} }
if err := verifyHeader(hdr, isRegular); err != nil { if err := verifyHeader(hdr, reader.DriveIsRegular); err != nil {
return err return err
} }
@@ -144,7 +139,7 @@ func Index(
} }
} }
curr, err := f.Seek(0, io.SeekCurrent) curr, err := reader.Drive.Seek(0, io.SeekCurrent)
if err != nil { if err != nil {
return err return err
} }
@@ -153,7 +148,7 @@ func Index(
return err return err
} }
currAndSize, err := f.Seek(0, io.SeekCurrent) currAndSize, err := reader.Drive.Seek(0, io.SeekCurrent)
if err != nil { if err != nil {
return err return err
} }
@@ -171,12 +166,12 @@ func Index(
} }
} else { } else {
// Seek to record // Seek to record
if err := mtio.SeekToRecordOnTape(f, int32(record)); err != nil { if err := mtio.SeekToRecordOnTape(drive.Drive, int32(record)); err != nil {
return err return err
} }
// Seek to block // Seek to block
br := bufio.NewReaderSize(f, mtio.BlockSize*recordSize) br := bufio.NewReaderSize(drive.Drive, mtio.BlockSize*recordSize)
if _, err := br.Read(make([]byte, block*mtio.BlockSize)); err != nil { if _, err := br.Read(make([]byte, block*mtio.BlockSize)); err != nil {
return err return err
} }
@@ -193,19 +188,19 @@ func Index(
hdr, err := tr.Next() hdr, err := tr.Next()
if err != nil { if err != nil {
if err == io.EOF { if err == io.EOF {
if err := mtio.GoToNextFileOnTape(f); err != nil { if err := mtio.GoToNextFileOnTape(drive.Drive); err != nil {
// EOD // EOD
break break
} }
record, err = mtio.GetCurrentRecordFromTape(f) record, err = mtio.GetCurrentRecordFromTape(drive.Drive)
if err != nil { if err != nil {
return err return err
} }
block = 0 block = 0
br = bufio.NewReaderSize(f, mtio.BlockSize*recordSize) br = bufio.NewReaderSize(drive.Drive, mtio.BlockSize*recordSize)
curr = int64(int64(recordSize) * mtio.BlockSize * record) curr = int64(int64(recordSize) * mtio.BlockSize * record)
counter = &ioext.CounterReader{Reader: br, BytesRead: int(curr)} counter = &ioext.CounterReader{Reader: br, BytesRead: int(curr)}
tr = tar.NewReader(counter) tr = tar.NewReader(counter)
@@ -221,7 +216,7 @@ func Index(
return err return err
} }
if err := verifyHeader(hdr, isRegular); err != nil { if err := verifyHeader(hdr, drive.DriveIsRegular); err != nil {
return err return err
} }

View File

@@ -13,13 +13,11 @@ import (
"github.com/pojntfx/stfs/internal/ioext" "github.com/pojntfx/stfs/internal/ioext"
"github.com/pojntfx/stfs/internal/mtio" "github.com/pojntfx/stfs/internal/mtio"
"github.com/pojntfx/stfs/internal/signature" "github.com/pojntfx/stfs/internal/signature"
"github.com/pojntfx/stfs/internal/tape"
"github.com/pojntfx/stfs/pkg/config" "github.com/pojntfx/stfs/pkg/config"
"github.com/pojntfx/stfs/pkg/hardware"
) )
func Query( func Query(
state hardware.DriveConfig, state config.DriveConfig,
pipes config.PipeConfig, pipes config.PipeConfig,
crypto config.CryptoConfig, crypto config.CryptoConfig,
@@ -29,21 +27,15 @@ func Query(
onHeader func(hdr *models.Header), onHeader func(hdr *models.Header),
) ([]*tar.Header, error) { ) ([]*tar.Header, error) {
f, isRegular, err := tape.OpenTapeReadOnly(state.Drive)
if err != nil {
return []*tar.Header{}, err
}
defer f.Close()
headers := []*tar.Header{} headers := []*tar.Header{}
if isRegular { if state.DriveIsRegular {
// Seek to record and block // Seek to record and block
if _, err := f.Seek(int64((recordSize*mtio.BlockSize*record)+block*mtio.BlockSize), 0); err != nil { if _, err := state.Drive.Seek(int64((recordSize*mtio.BlockSize*record)+block*mtio.BlockSize), 0); err != nil {
return []*tar.Header{}, err return []*tar.Header{}, err
} }
tr := tar.NewReader(f) tr := tar.NewReader(state.Drive)
record := int64(record) record := int64(record)
block := int64(block) block := int64(block)
@@ -52,7 +44,7 @@ func Query(
hdr, err := tr.Next() hdr, err := tr.Next()
if err != nil { if err != nil {
for { for {
curr, err := f.Seek(0, io.SeekCurrent) curr, err := state.Drive.Seek(0, io.SeekCurrent)
if err != nil { if err != nil {
return []*tar.Header{}, err return []*tar.Header{}, err
} }
@@ -70,11 +62,11 @@ func Query(
} }
// Seek to record and block // Seek to record and block
if _, err := f.Seek(int64((recordSize*mtio.BlockSize*int(record))+int(block)*mtio.BlockSize), io.SeekStart); err != nil { if _, err := state.Drive.Seek(int64((recordSize*mtio.BlockSize*int(record))+int(block)*mtio.BlockSize), io.SeekStart); err != nil {
return []*tar.Header{}, err return []*tar.Header{}, err
} }
tr = tar.NewReader(f) tr = tar.NewReader(state.Drive)
hdr, err = tr.Next() hdr, err = tr.Next()
if err != nil { if err != nil {
@@ -101,7 +93,7 @@ func Query(
return []*tar.Header{}, err return []*tar.Header{}, err
} }
if err := signature.VerifyHeader(hdr, isRegular, pipes.Signature, crypto.Recipient); err != nil { if err := signature.VerifyHeader(hdr, state.DriveIsRegular, pipes.Signature, crypto.Recipient); err != nil {
return []*tar.Header{}, err return []*tar.Header{}, err
} }
@@ -116,7 +108,7 @@ func Query(
headers = append(headers, hdr) headers = append(headers, hdr)
curr, err := f.Seek(0, io.SeekCurrent) curr, err := state.Drive.Seek(0, io.SeekCurrent)
if err != nil { if err != nil {
return []*tar.Header{}, err return []*tar.Header{}, err
} }
@@ -125,7 +117,7 @@ func Query(
return []*tar.Header{}, err return []*tar.Header{}, err
} }
currAndSize, err := f.Seek(0, io.SeekCurrent) currAndSize, err := state.Drive.Seek(0, io.SeekCurrent)
if err != nil { if err != nil {
return []*tar.Header{}, err return []*tar.Header{}, err
} }
@@ -141,12 +133,12 @@ func Query(
} }
} else { } else {
// Seek to record // Seek to record
if err := mtio.SeekToRecordOnTape(f, int32(record)); err != nil { if err := mtio.SeekToRecordOnTape(state.Drive, int32(record)); err != nil {
return []*tar.Header{}, err return []*tar.Header{}, err
} }
// Seek to block // Seek to block
br := bufio.NewReaderSize(f, mtio.BlockSize*recordSize) br := bufio.NewReaderSize(state.Drive, mtio.BlockSize*recordSize)
if _, err := br.Read(make([]byte, block*mtio.BlockSize)); err != nil { if _, err := br.Read(make([]byte, block*mtio.BlockSize)); err != nil {
return []*tar.Header{}, err return []*tar.Header{}, err
} }
@@ -162,19 +154,19 @@ func Query(
hdr, err := tr.Next() hdr, err := tr.Next()
if err != nil { if err != nil {
if err == io.EOF { if err == io.EOF {
if err := mtio.GoToNextFileOnTape(f); err != nil { if err := mtio.GoToNextFileOnTape(state.Drive); err != nil {
// EOD // EOD
break break
} }
record, err = mtio.GetCurrentRecordFromTape(f) record, err = mtio.GetCurrentRecordFromTape(state.Drive)
if err != nil { if err != nil {
return []*tar.Header{}, err return []*tar.Header{}, err
} }
block = 0 block = 0
br = bufio.NewReaderSize(f, mtio.BlockSize*recordSize) br = bufio.NewReaderSize(state.Drive, mtio.BlockSize*recordSize)
curr := int64(int64(recordSize) * mtio.BlockSize * record) curr := int64(int64(recordSize) * mtio.BlockSize * record)
counter := &ioext.CounterReader{Reader: br, BytesRead: int(curr)} counter := &ioext.CounterReader{Reader: br, BytesRead: int(curr)}
tr = tar.NewReader(counter) tr = tar.NewReader(counter)
@@ -189,7 +181,7 @@ func Query(
return []*tar.Header{}, err return []*tar.Header{}, err
} }
if err := signature.VerifyHeader(hdr, isRegular, pipes.Signature, crypto.Recipient); err != nil { if err := signature.VerifyHeader(hdr, state.DriveIsRegular, pipes.Signature, crypto.Recipient); err != nil {
return []*tar.Header{}, err return []*tar.Header{}, err
} }

75
pkg/tape/write.go Normal file
View File

@@ -0,0 +1,75 @@
package tape
import (
"os"
"github.com/pojntfx/stfs/internal/mtio"
)
func OpenTapeWriteOnly(drive string, recordSize int, overwrite bool) (f *os.File, isRegular bool, err error) {
stat, err := os.Stat(drive)
if err == nil {
isRegular = stat.Mode().IsRegular()
} else {
if os.IsNotExist(err) {
isRegular = true
} else {
return nil, false, err
}
}
if overwrite {
if isRegular {
f, err := os.OpenFile(drive, os.O_WRONLY|os.O_CREATE, 0600)
if err != nil {
return nil, false, err
}
// Clear the file's content
if err := f.Truncate(0); err != nil {
return nil, false, err
}
if err := f.Close(); err != nil {
return nil, false, err
}
} else {
f, err := os.OpenFile(drive, os.O_WRONLY, os.ModeCharDevice)
if err != nil {
return nil, false, err
}
// Seek to the start of the tape
if err := mtio.SeekToRecordOnTape(f, 0); err != nil {
return nil, false, err
}
if err := f.Close(); err != nil {
return nil, false, err
}
}
}
if isRegular {
f, err = os.OpenFile(drive, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
if err != nil {
return nil, false, err
}
// No need to go to end manually due to `os.O_APPEND`
} else {
f, err = os.OpenFile(drive, os.O_APPEND|os.O_WRONLY, os.ModeCharDevice)
if err != nil {
return nil, false, err
}
if !overwrite {
// Go to end of tape
if err := mtio.GoToEndOfTape(f); err != nil {
return nil, false, err
}
}
}
return f, isRegular, nil
}

View File

@@ -1,5 +0,0 @@
package utility
type PasswordConfig struct {
Password string
}

View File

@@ -15,7 +15,7 @@ import (
func Keygen( func Keygen(
pipes config.PipeConfig, pipes config.PipeConfig,
password PasswordConfig, password config.PasswordConfig,
) (privkey []byte, pubkey []byte, err error) { ) (privkey []byte, pubkey []byte, err error) {
if pipes.Encryption != config.NoneKey { if pipes.Encryption != config.NoneKey {
priv, pub, err := generateEncryptionKey(pipes.Encryption, password.Password) priv, pub, err := generateEncryptionKey(pipes.Encryption, password.Password)