From 58b407cd4fc826e197afaa97d2737b746c68e613 Mon Sep 17 00:00:00 2001 From: Felix Pojtinger Date: Mon, 13 Dec 2021 00:26:30 +0100 Subject: [PATCH] refactor: Use explicit reader/writer instead of filepath for drive --- cmd/stbak/cmd/archive.go | 45 +++++++++++++++---- cmd/stbak/cmd/delete.go | 35 +++++++++++++-- cmd/stbak/cmd/drive_eject.go | 15 ++++++- cmd/stbak/cmd/drive_tell.go | 15 ++++++- cmd/stbak/cmd/find.go | 3 +- cmd/stbak/cmd/keygen.go | 2 +- cmd/stbak/cmd/list.go | 3 +- cmd/stbak/cmd/move.go | 35 +++++++++++++-- cmd/stbak/cmd/recovery_fetch.go | 21 +++++++-- cmd/stbak/cmd/recovery_index.go | 22 +++++++-- cmd/stbak/cmd/recovery_query.go | 17 +++++-- cmd/stbak/cmd/restore.go | 22 +++++++-- cmd/stbak/cmd/update.go | 37 ++++++++++++--- internal/tape/write.go | 79 --------------------------------- internal/tarext/write.go | 46 +++++++++++++++++++ pkg/config/config.go | 27 ++++++++++- pkg/hardware/config.go | 5 --- pkg/hardware/eject.go | 13 ++---- pkg/hardware/tell.go | 13 ++---- pkg/inventory/config.go | 5 --- pkg/inventory/find.go | 3 +- pkg/inventory/list.go | 3 +- pkg/operations/archive.go | 70 ++++------------------------- pkg/operations/delete.go | 43 ++++++++++-------- pkg/operations/move.go | 43 ++++++++++-------- pkg/operations/restore.go | 12 ++--- pkg/operations/update.go | 20 ++++----- pkg/recovery/fetch.go | 25 ++++------- pkg/recovery/index.go | 45 +++++++++---------- pkg/recovery/query.go | 40 +++++++---------- {internal => pkg}/tape/read.go | 0 pkg/tape/write.go | 75 +++++++++++++++++++++++++++++++ pkg/utility/config.go | 5 --- pkg/utility/keygen.go | 2 +- 34 files changed, 506 insertions(+), 340 deletions(-) delete mode 100644 internal/tape/write.go create mode 100644 internal/tarext/write.go delete mode 100644 pkg/hardware/config.go delete mode 100644 pkg/inventory/config.go rename {internal => pkg}/tape/read.go (100%) create mode 100644 pkg/tape/write.go delete mode 100644 pkg/utility/config.go diff --git a/cmd/stbak/cmd/archive.go b/cmd/stbak/cmd/archive.go index c33fe7b..6eeb068 100644 --- a/cmd/stbak/cmd/archive.go +++ b/cmd/stbak/cmd/archive.go @@ -12,6 +12,7 @@ import ( "github.com/pojntfx/stfs/pkg/config" "github.com/pojntfx/stfs/pkg/operations" "github.com/pojntfx/stfs/pkg/recovery" + "github.com/pojntfx/stfs/pkg/tape" "github.com/spf13/cobra" "github.com/spf13/viper" ) @@ -30,7 +31,7 @@ var archiveCmd = &cobra.Command{ Use: "archive", Aliases: []string{"arc", "a", "c"}, 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 { return err } @@ -83,10 +84,27 @@ var archiveCmd = &cobra.Command{ 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( - config.StateConfig{ - Drive: viper.GetString(driveFlag), - Metadata: viper.GetString(metadataFlag), + config.DriveWriterConfig{ + Drive: writer, + DriveIsRegular: writerIsRegular, }, config.PipeConfig{ Compression: viper.GetString(compressionFlag), @@ -101,7 +119,6 @@ var archiveCmd = &cobra.Command{ viper.GetInt(recordSizeFlag), viper.GetString(fromFlag), - viper.GetBool(overwriteFlag), viper.GetString(compressionLevelFlag), logging.NewLogger().PrintHeader, @@ -110,9 +127,21 @@ var archiveCmd = &cobra.Command{ 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( - config.StateConfig{ - Drive: viper.GetString(driveFlag), + config.DriveReaderConfig{ + Drive: reader, + DriveIsRegular: readerIsRegular, + }, + config.DriveConfig{ + Drive: reader, + DriveIsRegular: readerIsRegular, + }, + config.MetadataConfig{ Metadata: viper.GetString(metadataFlag), }, config.PipeConfig{ @@ -130,7 +159,7 @@ var archiveCmd = &cobra.Command{ int(lastIndexedRecord), int(lastIndexedBlock), 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 { if len(hdrs) <= i { diff --git a/cmd/stbak/cmd/delete.go b/cmd/stbak/cmd/delete.go index a8bece6..364a7c8 100644 --- a/cmd/stbak/cmd/delete.go +++ b/cmd/stbak/cmd/delete.go @@ -5,6 +5,7 @@ import ( "github.com/pojntfx/stfs/internal/logging" "github.com/pojntfx/stfs/pkg/config" "github.com/pojntfx/stfs/pkg/operations" + "github.com/pojntfx/stfs/pkg/tape" "github.com/spf13/cobra" "github.com/spf13/viper" ) @@ -17,7 +18,7 @@ var deleteCmd = &cobra.Command{ Use: "delete", Aliases: []string{"del", "d", "rm"}, 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 { return err } @@ -49,9 +50,37 @@ var deleteCmd = &cobra.Command{ 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( - config.StateConfig{ - Drive: viper.GetString(driveFlag), + config.DriveWriterConfig{ + Drive: writer, + DriveIsRegular: writerIsRegular, + }, + config.DriveReaderConfig{ + Drive: reader, + DriveIsRegular: readerIsRegular, + }, + config.DriveConfig{ + Drive: reader, + DriveIsRegular: readerIsRegular, + }, + config.MetadataConfig{ Metadata: viper.GetString(metadataFlag), }, config.PipeConfig{ diff --git a/cmd/stbak/cmd/drive_eject.go b/cmd/stbak/cmd/drive_eject.go index 98d60a2..d07acd7 100644 --- a/cmd/stbak/cmd/drive_eject.go +++ b/cmd/stbak/cmd/drive_eject.go @@ -1,7 +1,9 @@ package cmd import ( + "github.com/pojntfx/stfs/pkg/config" "github.com/pojntfx/stfs/pkg/hardware" + "github.com/pojntfx/stfs/pkg/tape" "github.com/spf13/cobra" "github.com/spf13/viper" ) @@ -14,9 +16,18 @@ var driveEjectCmd = &cobra.Command{ return err } + reader, readerIsRegular, err := tape.OpenTapeReadOnly( + viper.GetString(driveFlag), + ) + if err != nil { + return nil + } + defer reader.Close() + return hardware.Eject( - hardware.DriveConfig{ - Drive: viper.GetString(driveFlag), + config.DriveConfig{ + Drive: reader, + DriveIsRegular: readerIsRegular, }, ) }, diff --git a/cmd/stbak/cmd/drive_tell.go b/cmd/stbak/cmd/drive_tell.go index 3925ee3..5334ad3 100644 --- a/cmd/stbak/cmd/drive_tell.go +++ b/cmd/stbak/cmd/drive_tell.go @@ -3,7 +3,9 @@ package cmd import ( "fmt" + "github.com/pojntfx/stfs/pkg/config" "github.com/pojntfx/stfs/pkg/hardware" + "github.com/pojntfx/stfs/pkg/tape" "github.com/spf13/cobra" "github.com/spf13/viper" ) @@ -16,9 +18,18 @@ var driveTellCmd = &cobra.Command{ return err } + reader, readerIsRegular, err := tape.OpenTapeReadOnly( + viper.GetString(driveFlag), + ) + if err != nil { + return nil + } + defer reader.Close() + currentRecord, err := hardware.Tell( - hardware.DriveConfig{ - Drive: viper.GetString(driveFlag), + config.DriveConfig{ + Drive: reader, + DriveIsRegular: readerIsRegular, }, ) if err != nil { diff --git a/cmd/stbak/cmd/find.go b/cmd/stbak/cmd/find.go index 0878909..712bcb9 100644 --- a/cmd/stbak/cmd/find.go +++ b/cmd/stbak/cmd/find.go @@ -2,6 +2,7 @@ package cmd import ( "github.com/pojntfx/stfs/internal/logging" + "github.com/pojntfx/stfs/pkg/config" "github.com/pojntfx/stfs/pkg/inventory" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -21,7 +22,7 @@ var findCmd = &cobra.Command{ } if _, err := inventory.Find( - inventory.MetadataConfig{ + config.MetadataConfig{ Metadata: viper.GetString(metadataFlag), }, diff --git a/cmd/stbak/cmd/keygen.go b/cmd/stbak/cmd/keygen.go index f73aad2..4a143a3 100644 --- a/cmd/stbak/cmd/keygen.go +++ b/cmd/stbak/cmd/keygen.go @@ -26,7 +26,7 @@ var keygenCmd = &cobra.Command{ Encryption: viper.GetString(encryptionFlag), Signature: viper.GetString(signatureFlag), }, - utility.PasswordConfig{ + config.PasswordConfig{ Password: viper.GetString(passwordFlag), }, ) diff --git a/cmd/stbak/cmd/list.go b/cmd/stbak/cmd/list.go index 9952deb..1354c67 100644 --- a/cmd/stbak/cmd/list.go +++ b/cmd/stbak/cmd/list.go @@ -2,6 +2,7 @@ package cmd import ( "github.com/pojntfx/stfs/internal/logging" + "github.com/pojntfx/stfs/pkg/config" "github.com/pojntfx/stfs/pkg/inventory" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -17,7 +18,7 @@ var listCmd = &cobra.Command{ } if _, err := inventory.List( - inventory.MetadataConfig{ + config.MetadataConfig{ Metadata: viper.GetString(metadataFlag), }, diff --git a/cmd/stbak/cmd/move.go b/cmd/stbak/cmd/move.go index c0a177d..85a8a71 100644 --- a/cmd/stbak/cmd/move.go +++ b/cmd/stbak/cmd/move.go @@ -5,6 +5,7 @@ import ( "github.com/pojntfx/stfs/internal/logging" "github.com/pojntfx/stfs/pkg/config" "github.com/pojntfx/stfs/pkg/operations" + "github.com/pojntfx/stfs/pkg/tape" "github.com/spf13/cobra" "github.com/spf13/viper" ) @@ -13,7 +14,7 @@ var moveCmd = &cobra.Command{ Use: "move", Aliases: []string{"mov", "m", "mv"}, 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 { return err } @@ -45,9 +46,37 @@ var moveCmd = &cobra.Command{ 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( - config.StateConfig{ - Drive: viper.GetString(driveFlag), + config.DriveWriterConfig{ + Drive: writer, + DriveIsRegular: writerIsRegular, + }, + config.DriveConfig{ + Drive: reader, + DriveIsRegular: readerIsRegular, + }, + config.DriveReaderConfig{ + Drive: reader, + DriveIsRegular: readerIsRegular, + }, + config.MetadataConfig{ Metadata: viper.GetString(metadataFlag), }, config.PipeConfig{ diff --git a/cmd/stbak/cmd/recovery_fetch.go b/cmd/stbak/cmd/recovery_fetch.go index a0379e0..0d47261 100644 --- a/cmd/stbak/cmd/recovery_fetch.go +++ b/cmd/stbak/cmd/recovery_fetch.go @@ -4,8 +4,8 @@ import ( "github.com/pojntfx/stfs/internal/keys" "github.com/pojntfx/stfs/internal/logging" "github.com/pojntfx/stfs/pkg/config" - "github.com/pojntfx/stfs/pkg/hardware" "github.com/pojntfx/stfs/pkg/recovery" + "github.com/pojntfx/stfs/pkg/tape" "github.com/spf13/cobra" "github.com/spf13/viper" ) @@ -20,7 +20,7 @@ const ( var recoveryFetchCmd = &cobra.Command{ Use: "fetch", 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 { return err } @@ -52,9 +52,22 @@ var recoveryFetchCmd = &cobra.Command{ return err } + reader, readerIsRegular, err := tape.OpenTapeReadOnly( + viper.GetString(driveFlag), + ) + if err != nil { + return nil + } + defer reader.Close() + return recovery.Fetch( - hardware.DriveConfig{ - Drive: viper.GetString(driveFlag), + config.DriveReaderConfig{ + Drive: reader, + DriveIsRegular: readerIsRegular, + }, + config.DriveConfig{ + Drive: reader, + DriveIsRegular: readerIsRegular, }, config.PipeConfig{ Compression: viper.GetString(compressionFlag), diff --git a/cmd/stbak/cmd/recovery_index.go b/cmd/stbak/cmd/recovery_index.go index 734ff46..0ab17e7 100644 --- a/cmd/stbak/cmd/recovery_index.go +++ b/cmd/stbak/cmd/recovery_index.go @@ -9,6 +9,7 @@ import ( "github.com/pojntfx/stfs/internal/signature" "github.com/pojntfx/stfs/pkg/config" "github.com/pojntfx/stfs/pkg/recovery" + "github.com/pojntfx/stfs/pkg/tape" "github.com/spf13/cobra" "github.com/spf13/viper" ) @@ -16,7 +17,7 @@ import ( var recoveryIndexCmd = &cobra.Command{ Use: "index", 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 { return err } @@ -48,9 +49,24 @@ var recoveryIndexCmd = &cobra.Command{ return err } + reader, readerIsRegular, err := tape.OpenTapeReadOnly( + viper.GetString(driveFlag), + ) + if err != nil { + return nil + } + defer reader.Close() + return recovery.Index( - config.StateConfig{ - Drive: viper.GetString(driveFlag), + config.DriveReaderConfig{ + Drive: reader, + DriveIsRegular: readerIsRegular, + }, + config.DriveConfig{ + Drive: reader, + DriveIsRegular: readerIsRegular, + }, + config.MetadataConfig{ Metadata: viper.GetString(metadataFlag), }, config.PipeConfig{ diff --git a/cmd/stbak/cmd/recovery_query.go b/cmd/stbak/cmd/recovery_query.go index a176985..2b604b3 100644 --- a/cmd/stbak/cmd/recovery_query.go +++ b/cmd/stbak/cmd/recovery_query.go @@ -4,8 +4,8 @@ import ( "github.com/pojntfx/stfs/internal/keys" "github.com/pojntfx/stfs/internal/logging" "github.com/pojntfx/stfs/pkg/config" - "github.com/pojntfx/stfs/pkg/hardware" "github.com/pojntfx/stfs/pkg/recovery" + "github.com/pojntfx/stfs/pkg/tape" "github.com/spf13/cobra" "github.com/spf13/viper" ) @@ -13,7 +13,7 @@ import ( var recoveryQueryCmd = &cobra.Command{ Use: "query", 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 { return err } @@ -45,9 +45,18 @@ var recoveryQueryCmd = &cobra.Command{ return err } + reader, readerIsRegular, err := tape.OpenTapeReadOnly( + viper.GetString(driveFlag), + ) + if err != nil { + return nil + } + defer reader.Close() + if _, err := recovery.Query( - hardware.DriveConfig{ - Drive: viper.GetString(driveFlag), + config.DriveConfig{ + Drive: reader, + DriveIsRegular: readerIsRegular, }, config.PipeConfig{ Compression: viper.GetString(compressionFlag), diff --git a/cmd/stbak/cmd/restore.go b/cmd/stbak/cmd/restore.go index 64d8d6f..99c9a9a 100644 --- a/cmd/stbak/cmd/restore.go +++ b/cmd/stbak/cmd/restore.go @@ -5,6 +5,7 @@ import ( "github.com/pojntfx/stfs/internal/logging" "github.com/pojntfx/stfs/pkg/config" "github.com/pojntfx/stfs/pkg/operations" + "github.com/pojntfx/stfs/pkg/tape" "github.com/spf13/cobra" "github.com/spf13/viper" ) @@ -17,7 +18,7 @@ var restoreCmd = &cobra.Command{ Use: "restore", Aliases: []string{"res", "r", "x"}, 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 { return err } @@ -49,9 +50,24 @@ var restoreCmd = &cobra.Command{ return err } + reader, readerIsRegular, err := tape.OpenTapeReadOnly( + viper.GetString(driveFlag), + ) + if err != nil { + return nil + } + defer reader.Close() + return operations.Restore( - config.StateConfig{ - Drive: viper.GetString(driveFlag), + config.DriveReaderConfig{ + Drive: reader, + DriveIsRegular: readerIsRegular, + }, + config.DriveConfig{ + Drive: reader, + DriveIsRegular: readerIsRegular, + }, + config.MetadataConfig{ Metadata: viper.GetString(metadataFlag), }, config.PipeConfig{ diff --git a/cmd/stbak/cmd/update.go b/cmd/stbak/cmd/update.go index fade11d..e5ea8df 100644 --- a/cmd/stbak/cmd/update.go +++ b/cmd/stbak/cmd/update.go @@ -12,6 +12,7 @@ import ( "github.com/pojntfx/stfs/pkg/config" "github.com/pojntfx/stfs/pkg/operations" "github.com/pojntfx/stfs/pkg/recovery" + "github.com/pojntfx/stfs/pkg/tape" "github.com/spf13/cobra" "github.com/spf13/viper" ) @@ -20,7 +21,7 @@ var updateCmd = &cobra.Command{ Use: "update", Aliases: []string{"upd", "u"}, 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 { return err } @@ -66,10 +67,27 @@ var updateCmd = &cobra.Command{ 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( - config.StateConfig{ - Drive: viper.GetString(driveFlag), - Metadata: viper.GetString(metadataFlag), + config.DriveWriterConfig{ + Drive: writer, + DriveIsRegular: writerIsRegular, }, config.PipeConfig{ Compression: viper.GetString(compressionFlag), @@ -94,8 +112,15 @@ var updateCmd = &cobra.Command{ } return recovery.Index( - config.StateConfig{ - Drive: viper.GetString(driveFlag), + config.DriveReaderConfig{ + Drive: reader, + DriveIsRegular: readerIsRegular, + }, + config.DriveConfig{ + Drive: reader, + DriveIsRegular: readerIsRegular, + }, + config.MetadataConfig{ Metadata: viper.GetString(metadataFlag), }, config.PipeConfig{ diff --git a/internal/tape/write.go b/internal/tape/write.go deleted file mode 100644 index f6bfc26..0000000 --- a/internal/tape/write.go +++ /dev/null @@ -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 -} diff --git a/internal/tarext/write.go b/internal/tarext/write.go new file mode 100644 index 0000000..d6adfba --- /dev/null +++ b/internal/tarext/write.go @@ -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 +} diff --git a/pkg/config/config.go b/pkg/config/config.go index 8671c16..756ecb1 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -1,7 +1,26 @@ package config -type StateConfig struct { - Drive string +import ( + "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 } @@ -16,3 +35,7 @@ type CryptoConfig struct { Identity interface{} Password string } + +type PasswordConfig struct { + Password string +} diff --git a/pkg/hardware/config.go b/pkg/hardware/config.go deleted file mode 100644 index 8d0bf19..0000000 --- a/pkg/hardware/config.go +++ /dev/null @@ -1,5 +0,0 @@ -package hardware - -type DriveConfig struct { - Drive string -} diff --git a/pkg/hardware/eject.go b/pkg/hardware/eject.go index 7dad6c0..384e9b5 100644 --- a/pkg/hardware/eject.go +++ b/pkg/hardware/eject.go @@ -1,19 +1,12 @@ package hardware import ( - "os" - "github.com/pojntfx/stfs/internal/mtio" + "github.com/pojntfx/stfs/pkg/config" ) func Eject( - state DriveConfig, + state config.DriveConfig, ) error { - f, err := os.OpenFile(state.Drive, os.O_RDONLY, os.ModeCharDevice) - if err != nil { - return err - } - defer f.Close() - - return mtio.EjectTape(f) + return mtio.EjectTape(state.Drive) } diff --git a/pkg/hardware/tell.go b/pkg/hardware/tell.go index 13f33de..1506ffc 100644 --- a/pkg/hardware/tell.go +++ b/pkg/hardware/tell.go @@ -1,19 +1,12 @@ package hardware import ( - "os" - "github.com/pojntfx/stfs/internal/mtio" + "github.com/pojntfx/stfs/pkg/config" ) func Tell( - state DriveConfig, + state config.DriveConfig, ) (int64, error) { - f, err := os.OpenFile(state.Drive, os.O_RDONLY, os.ModeCharDevice) - if err != nil { - return -1, err - } - defer f.Close() - - return mtio.GetCurrentRecordFromTape(f) + return mtio.GetCurrentRecordFromTape(state.Drive) } diff --git a/pkg/inventory/config.go b/pkg/inventory/config.go deleted file mode 100644 index eead210..0000000 --- a/pkg/inventory/config.go +++ /dev/null @@ -1,5 +0,0 @@ -package inventory - -type MetadataConfig struct { - Metadata string -} diff --git a/pkg/inventory/find.go b/pkg/inventory/find.go index 8c12f6a..148649b 100644 --- a/pkg/inventory/find.go +++ b/pkg/inventory/find.go @@ -8,10 +8,11 @@ import ( "github.com/pojntfx/stfs/internal/converters" models "github.com/pojntfx/stfs/internal/db/sqlite/models/metadata" "github.com/pojntfx/stfs/internal/persisters" + "github.com/pojntfx/stfs/pkg/config" ) func Find( - state MetadataConfig, + state config.MetadataConfig, expression string, diff --git a/pkg/inventory/list.go b/pkg/inventory/list.go index 7c19207..412ba89 100644 --- a/pkg/inventory/list.go +++ b/pkg/inventory/list.go @@ -7,10 +7,11 @@ import ( "github.com/pojntfx/stfs/internal/converters" models "github.com/pojntfx/stfs/internal/db/sqlite/models/metadata" "github.com/pojntfx/stfs/internal/persisters" + "github.com/pojntfx/stfs/pkg/config" ) func List( - state MetadataConfig, + state config.MetadataConfig, name string, diff --git a/pkg/operations/archive.go b/pkg/operations/archive.go index 7164af4..62c684d 100644 --- a/pkg/operations/archive.go +++ b/pkg/operations/archive.go @@ -20,7 +20,7 @@ import ( "github.com/pojntfx/stfs/internal/signature" "github.com/pojntfx/stfs/internal/statext" "github.com/pojntfx/stfs/internal/suffix" - "github.com/pojntfx/stfs/internal/tape" + "github.com/pojntfx/stfs/internal/tarext" "github.com/pojntfx/stfs/pkg/config" ) @@ -29,73 +29,21 @@ var ( ) func Archive( - state config.StateConfig, + writer config.DriveWriterConfig, pipes config.PipeConfig, crypto config.CryptoConfig, recordSize int, from string, - overwrite bool, compressionLevel string, onHeader func(hdr *models.Header), ) ([]*tar.Header, error) { 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 { 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) headers := []*tar.Header{} @@ -143,7 +91,7 @@ func Archive( encryptor, pipes.Compression, compressionLevel, - isRegular, + writer.DriveIsRegular, recordSize, ) if err != nil { @@ -155,12 +103,12 @@ func Archive( 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 { return err } - if isRegular { + if writer.DriveIsRegular { if _, err := io.Copy(compressor, signer); err != nil { return err } @@ -219,7 +167,7 @@ func Archive( hdrToAppend := *hdr 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 } @@ -247,7 +195,7 @@ func Archive( encryptor, pipes.Compression, compressionLevel, - isRegular, + writer.DriveIsRegular, recordSize, ) if err != nil { @@ -259,7 +207,7 @@ func Archive( return err } - if isRegular { + if writer.DriveIsRegular { if _, err := io.Copy(compressor, file); err != nil { return err } diff --git a/pkg/operations/delete.go b/pkg/operations/delete.go index 5f7941b..3b23301 100644 --- a/pkg/operations/delete.go +++ b/pkg/operations/delete.go @@ -10,13 +10,16 @@ import ( "github.com/pojntfx/stfs/internal/persisters" "github.com/pojntfx/stfs/internal/records" "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/recovery" ) func Delete( - state config.StateConfig, + writer config.DriveWriterConfig, + reader config.DriveReaderConfig, + drive config.DriveConfig, + metadata config.MetadataConfig, pipes config.PipeConfig, crypto config.CryptoConfig, @@ -26,13 +29,13 @@ func Delete( onHeader func(hdr *models.Header), ) error { 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 { return err } defer cleanup(&dirty) - metadataPersister := persisters.NewMetadataPersister(state.Metadata) + metadataPersister := persisters.NewMetadataPersister(metadata.Metadata) if err := metadataPersister.Open(); err != nil { return err } @@ -60,7 +63,7 @@ func Delete( } // Append deletion hdrs to the tape or tar file - hdrs := []*tar.Header{} + hdrs := []tar.Header{} for _, dbhdr := range headersToDelete { hdr, err := converters.DBHeaderToTarHeader(dbhdr) if err != nil { @@ -71,7 +74,18 @@ func Delete( hdr.PAXRecords[records.STFSRecordVersion] = records.STFSRecordVersion1 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 } @@ -84,21 +98,12 @@ func Delete( } 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( - state, + reader, + drive, + metadata, pipes, crypto, @@ -113,7 +118,7 @@ func Delete( return config.ErrTarHeaderMissing } - *hdr = *hdrs[i] + *hdr = hdrs[i] return nil }, diff --git a/pkg/operations/move.go b/pkg/operations/move.go index d5d5539..3357e68 100644 --- a/pkg/operations/move.go +++ b/pkg/operations/move.go @@ -11,13 +11,16 @@ import ( "github.com/pojntfx/stfs/internal/persisters" "github.com/pojntfx/stfs/internal/records" "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/recovery" ) func Move( - state config.StateConfig, + writer config.DriveWriterConfig, + drive config.DriveConfig, + reader config.DriveReaderConfig, + metadata config.MetadataConfig, pipes config.PipeConfig, crypto config.CryptoConfig, @@ -28,13 +31,13 @@ func Move( onHeader func(hdr *models.Header), ) error { 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 { return err } defer cleanup(&dirty) - metadataPersister := persisters.NewMetadataPersister(state.Metadata) + metadataPersister := persisters.NewMetadataPersister(metadata.Metadata) if err := metadataPersister.Open(); err != nil { return err } @@ -62,7 +65,7 @@ func Move( } // Append move headers to the tape or tar file - hdrs := []*tar.Header{} + hdrs := []tar.Header{} for _, dbhdr := range headersToMove { hdr, err := converters.DBHeaderToTarHeader(dbhdr) if err != nil { @@ -75,7 +78,18 @@ func Move( hdr.PAXRecords[records.STFSRecordAction] = records.STFSRecordActionUpdate 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 } @@ -88,21 +102,12 @@ func Move( } 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( - state, + reader, + drive, + metadata, pipes, crypto, @@ -117,7 +122,7 @@ func Move( return config.ErrTarHeaderMissing } - *hdr = *hdrs[i] + *hdr = hdrs[i] return nil }, diff --git a/pkg/operations/restore.go b/pkg/operations/restore.go index cf205bb..8da7297 100644 --- a/pkg/operations/restore.go +++ b/pkg/operations/restore.go @@ -11,12 +11,13 @@ import ( models "github.com/pojntfx/stfs/internal/db/sqlite/models/metadata" "github.com/pojntfx/stfs/internal/persisters" "github.com/pojntfx/stfs/pkg/config" - "github.com/pojntfx/stfs/pkg/hardware" "github.com/pojntfx/stfs/pkg/recovery" ) func Restore( - state config.StateConfig, + reader config.DriveReaderConfig, + drive config.DriveConfig, + metadata config.MetadataConfig, pipes config.PipeConfig, crypto config.CryptoConfig, @@ -27,7 +28,7 @@ func Restore( onHeader func(hdr *models.Header), ) error { - metadataPersister := persisters.NewMetadataPersister(state.Metadata) + metadataPersister := persisters.NewMetadataPersister(metadata.Metadata) if err := metadataPersister.Open(); err != nil { return err } @@ -78,9 +79,8 @@ func Restore( } if err := recovery.Fetch( - hardware.DriveConfig{ - Drive: state.Drive, - }, + reader, + drive, pipes, crypto, diff --git a/pkg/operations/update.go b/pkg/operations/update.go index 383f3a8..7b40264 100644 --- a/pkg/operations/update.go +++ b/pkg/operations/update.go @@ -18,12 +18,12 @@ import ( "github.com/pojntfx/stfs/internal/signature" "github.com/pojntfx/stfs/internal/statext" "github.com/pojntfx/stfs/internal/suffix" - "github.com/pojntfx/stfs/internal/tape" + "github.com/pojntfx/stfs/internal/tarext" "github.com/pojntfx/stfs/pkg/config" ) func Update( - state config.StateConfig, + writer config.DriveWriterConfig, pipes config.PipeConfig, crypto config.CryptoConfig, @@ -35,7 +35,7 @@ func Update( onHeader func(hdr *models.Header), ) ([]*tar.Header, error) { 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 { return []*tar.Header{}, err } @@ -86,7 +86,7 @@ func Update( encryptor, pipes.Compression, compressionLevel, - isRegular, + writer.DriveIsRegular, recordSize, ) if err != nil { @@ -98,12 +98,12 @@ func Update( 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 { return err } - if isRegular { + if writer.DriveIsRegular { if _, err := io.Copy(compressor, signer); err != nil { return err } @@ -165,7 +165,7 @@ func Update( hdrToAppend := *hdr 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 } @@ -191,7 +191,7 @@ func Update( encryptor, pipes.Compression, compressionLevel, - isRegular, + writer.DriveIsRegular, recordSize, ) if err != nil { @@ -203,7 +203,7 @@ func Update( return err } - if isRegular { + if writer.DriveIsRegular { if _, err := io.Copy(compressor, file); err != nil { return err } @@ -244,7 +244,7 @@ func Update( hdrToAppend := *hdr 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 } diff --git a/pkg/recovery/fetch.go b/pkg/recovery/fetch.go index f2d9274..22a3825 100644 --- a/pkg/recovery/fetch.go +++ b/pkg/recovery/fetch.go @@ -14,13 +14,12 @@ import ( "github.com/pojntfx/stfs/internal/mtio" "github.com/pojntfx/stfs/internal/records" "github.com/pojntfx/stfs/internal/signature" - "github.com/pojntfx/stfs/internal/tape" "github.com/pojntfx/stfs/pkg/config" - "github.com/pojntfx/stfs/pkg/hardware" ) func Fetch( - state hardware.DriveConfig, + reader config.DriveReaderConfig, + drive config.DriveConfig, pipes config.PipeConfig, crypto config.CryptoConfig, @@ -32,28 +31,22 @@ func Fetch( onHeader func(hdr *models.Header), ) error { - f, isRegular, err := tape.OpenTapeReadOnly(state.Drive) - if err != nil { - return err - } - defer f.Close() - var tr *tar.Reader - if isRegular { + if reader.DriveIsRegular { // 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 } - tr = tar.NewReader(f) + tr = tar.NewReader(reader.Drive) } else { // Seek to record - if err := mtio.SeekToRecordOnTape(f, int32(record)); err != nil { + if err := mtio.SeekToRecordOnTape(drive.Drive, int32(record)); err != nil { return err } // 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 { return err } @@ -70,7 +63,7 @@ func Fetch( 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 } @@ -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 { return err } diff --git a/pkg/recovery/index.go b/pkg/recovery/index.go index 8d10d9e..47c27c9 100644 --- a/pkg/recovery/index.go +++ b/pkg/recovery/index.go @@ -18,12 +18,13 @@ import ( "github.com/pojntfx/stfs/internal/persisters" "github.com/pojntfx/stfs/internal/records" "github.com/pojntfx/stfs/internal/suffix" - "github.com/pojntfx/stfs/internal/tape" "github.com/pojntfx/stfs/pkg/config" ) func Index( - state config.StateConfig, + reader config.DriveReaderConfig, + drive config.DriveConfig, + metadata config.MetadataConfig, pipes config.PipeConfig, crypto config.CryptoConfig, @@ -45,7 +46,7 @@ func Index( onHeader func(hdr *models.Header), ) error { 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 { return err } @@ -59,24 +60,18 @@ func Index( } } - metadataPersister := persisters.NewMetadataPersister(state.Metadata) + metadataPersister := persisters.NewMetadataPersister(metadata.Metadata) if err := metadataPersister.Open(); err != nil { return err } - f, isRegular, err := tape.OpenTapeReadOnly(state.Drive) - if err != nil { - return err - } - defer f.Close() - - if isRegular { + if reader.DriveIsRegular { // 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 } - tr := tar.NewReader(f) + tr := tar.NewReader(reader.Drive) record := int64(record) block := int64(block) @@ -86,7 +81,7 @@ func Index( hdr, err := tr.Next() if err != nil { for { - curr, err := f.Seek(0, io.SeekCurrent) + curr, err := reader.Drive.Seek(0, io.SeekCurrent) if err != nil { return err } @@ -104,11 +99,11 @@ func Index( } // 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 } - tr = tar.NewReader(f) + tr = tar.NewReader(reader.Drive) hdr, err = tr.Next() if err != nil { @@ -135,7 +130,7 @@ func Index( return err } - if err := verifyHeader(hdr, isRegular); err != nil { + if err := verifyHeader(hdr, reader.DriveIsRegular); err != nil { 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 { return err } @@ -153,7 +148,7 @@ func Index( return err } - currAndSize, err := f.Seek(0, io.SeekCurrent) + currAndSize, err := reader.Drive.Seek(0, io.SeekCurrent) if err != nil { return err } @@ -171,12 +166,12 @@ func Index( } } else { // Seek to record - if err := mtio.SeekToRecordOnTape(f, int32(record)); err != nil { + if err := mtio.SeekToRecordOnTape(drive.Drive, int32(record)); err != nil { return err } // 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 { return err } @@ -193,19 +188,19 @@ func Index( hdr, err := tr.Next() if err != nil { if err == io.EOF { - if err := mtio.GoToNextFileOnTape(f); err != nil { + if err := mtio.GoToNextFileOnTape(drive.Drive); err != nil { // EOD break } - record, err = mtio.GetCurrentRecordFromTape(f) + record, err = mtio.GetCurrentRecordFromTape(drive.Drive) if err != nil { return err } block = 0 - br = bufio.NewReaderSize(f, mtio.BlockSize*recordSize) + br = bufio.NewReaderSize(drive.Drive, mtio.BlockSize*recordSize) curr = int64(int64(recordSize) * mtio.BlockSize * record) counter = &ioext.CounterReader{Reader: br, BytesRead: int(curr)} tr = tar.NewReader(counter) @@ -221,7 +216,7 @@ func Index( return err } - if err := verifyHeader(hdr, isRegular); err != nil { + if err := verifyHeader(hdr, drive.DriveIsRegular); err != nil { return err } diff --git a/pkg/recovery/query.go b/pkg/recovery/query.go index 69911fa..dd15ba6 100644 --- a/pkg/recovery/query.go +++ b/pkg/recovery/query.go @@ -13,13 +13,11 @@ import ( "github.com/pojntfx/stfs/internal/ioext" "github.com/pojntfx/stfs/internal/mtio" "github.com/pojntfx/stfs/internal/signature" - "github.com/pojntfx/stfs/internal/tape" "github.com/pojntfx/stfs/pkg/config" - "github.com/pojntfx/stfs/pkg/hardware" ) func Query( - state hardware.DriveConfig, + state config.DriveConfig, pipes config.PipeConfig, crypto config.CryptoConfig, @@ -29,21 +27,15 @@ func Query( onHeader func(hdr *models.Header), ) ([]*tar.Header, error) { - f, isRegular, err := tape.OpenTapeReadOnly(state.Drive) - if err != nil { - return []*tar.Header{}, err - } - defer f.Close() - headers := []*tar.Header{} - if isRegular { + if state.DriveIsRegular { // 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 } - tr := tar.NewReader(f) + tr := tar.NewReader(state.Drive) record := int64(record) block := int64(block) @@ -52,7 +44,7 @@ func Query( hdr, err := tr.Next() if err != nil { for { - curr, err := f.Seek(0, io.SeekCurrent) + curr, err := state.Drive.Seek(0, io.SeekCurrent) if err != nil { return []*tar.Header{}, err } @@ -70,11 +62,11 @@ func Query( } // 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 } - tr = tar.NewReader(f) + tr = tar.NewReader(state.Drive) hdr, err = tr.Next() if err != nil { @@ -101,7 +93,7 @@ func Query( 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 } @@ -116,7 +108,7 @@ func Query( headers = append(headers, hdr) - curr, err := f.Seek(0, io.SeekCurrent) + curr, err := state.Drive.Seek(0, io.SeekCurrent) if err != nil { return []*tar.Header{}, err } @@ -125,7 +117,7 @@ func Query( return []*tar.Header{}, err } - currAndSize, err := f.Seek(0, io.SeekCurrent) + currAndSize, err := state.Drive.Seek(0, io.SeekCurrent) if err != nil { return []*tar.Header{}, err } @@ -141,12 +133,12 @@ func Query( } } else { // 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 } // 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 { return []*tar.Header{}, err } @@ -162,19 +154,19 @@ func Query( hdr, err := tr.Next() if err != nil { if err == io.EOF { - if err := mtio.GoToNextFileOnTape(f); err != nil { + if err := mtio.GoToNextFileOnTape(state.Drive); err != nil { // EOD break } - record, err = mtio.GetCurrentRecordFromTape(f) + record, err = mtio.GetCurrentRecordFromTape(state.Drive) if err != nil { return []*tar.Header{}, err } block = 0 - br = bufio.NewReaderSize(f, mtio.BlockSize*recordSize) + br = bufio.NewReaderSize(state.Drive, mtio.BlockSize*recordSize) curr := int64(int64(recordSize) * mtio.BlockSize * record) counter := &ioext.CounterReader{Reader: br, BytesRead: int(curr)} tr = tar.NewReader(counter) @@ -189,7 +181,7 @@ func Query( 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 } diff --git a/internal/tape/read.go b/pkg/tape/read.go similarity index 100% rename from internal/tape/read.go rename to pkg/tape/read.go diff --git a/pkg/tape/write.go b/pkg/tape/write.go new file mode 100644 index 0000000..4be2098 --- /dev/null +++ b/pkg/tape/write.go @@ -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 +} diff --git a/pkg/utility/config.go b/pkg/utility/config.go deleted file mode 100644 index c3e47fa..0000000 --- a/pkg/utility/config.go +++ /dev/null @@ -1,5 +0,0 @@ -package utility - -type PasswordConfig struct { - Password string -} diff --git a/pkg/utility/keygen.go b/pkg/utility/keygen.go index 2467c03..08279cf 100644 --- a/pkg/utility/keygen.go +++ b/pkg/utility/keygen.go @@ -15,7 +15,7 @@ import ( func Keygen( pipes config.PipeConfig, - password PasswordConfig, + password config.PasswordConfig, ) (privkey []byte, pubkey []byte, err error) { if pipes.Encryption != config.NoneKey { priv, pub, err := generateEncryptionKey(pipes.Encryption, password.Password)