diff --git a/tar/asm/assemble.go b/tar/asm/assemble.go index 41fafc2..7f20a16 100644 --- a/tar/asm/assemble.go +++ b/tar/asm/assemble.go @@ -6,7 +6,18 @@ import ( "github.com/vbatts/tar-split/tar/storage" ) -func NewTarStream(fg FileGetter, up storage.Unpacker) io.ReadCloser { +// NewOutputTarStream returns an io.ReadCloser that is an assemble tar archive +// stream. +// +// It takes a FileGetter, for mapping the file payloads that are to be read in, +// and a storage.Unpacker, which has access to the rawbytes and file order +// metadata. With the combination of these two items, a precise assembled Tar +// archive is possible. +func NewOutputTarStream(fg FileGetter, up storage.Unpacker) io.ReadCloser { + // ... Since these are interfaces, this is possible, so let's not have a nil pointer + if fg == nil || up == nil { + return nil + } pr, pw := io.Pipe() go func() { for { diff --git a/tar/asm/assemble_test.go b/tar/asm/assemble_test.go new file mode 100644 index 0000000..81dff9f --- /dev/null +++ b/tar/asm/assemble_test.go @@ -0,0 +1,9 @@ +package asm + +import "testing" + +func TestNewOutputTarStream(t *testing.T) { + // TODO disassembly + fgp := NewBufferFileGetPutter() + _ = NewOutputTarStream(fgp, nil) +} diff --git a/tar/asm/disassemble.go b/tar/asm/disassemble.go new file mode 100644 index 0000000..35fb61a --- /dev/null +++ b/tar/asm/disassemble.go @@ -0,0 +1,34 @@ +package asm + +import ( + "io" + + "github.com/vbatts/tar-split/archive/tar" + "github.com/vbatts/tar-split/tar/storage" +) + +func NewInputTarStream(r io.Reader, fp FilePutter, p storage.Packer) (io.Reader, error) { + // What to do here... folks will want their own access to the Reader that is + // their tar archive stream, but we'll need that same stream to use our + // forked 'archive/tar'. + // Perhaps do an io.TeeReader that hand back an io.Reader for them to read + // from, and we'll mitm the stream to store metadata. + // We'll need a FilePutter too ... + + // Another concern, whether to do any FilePutter operations, such that we + // don't extract any amount of the archive. But then again, we're not making + // files/directories, hardlinks, etc. Just writing the io to the FilePutter. + // Perhaps we have a DiscardFilePutter that is a bit bucket. + + // we'll return the pipe reader, since TeeReader does not buffer and will + // only read what the outputRdr Read's. Since Tar archive's have padding on + // the end, we want to be the one reading the padding, even if the user's + // `archive/tar` doesn't care. + pR, pW := io.Pipe() + outputRdr := io.TeeReader(r, pW) + + tr := tar.NewReader(outputRdr) + tr.RawAccounting = true + + return pR, nil +} diff --git a/tar/asm/getter.go b/tar/asm/getter.go index bb5e0d1..2b94c89 100644 --- a/tar/asm/getter.go +++ b/tar/asm/getter.go @@ -4,6 +4,7 @@ import ( "bytes" "errors" "io" + "io/ioutil" "os" "path" ) @@ -73,3 +74,16 @@ func NewBufferFileGetPutter() FileGetPutter { files: map[string][]byte{}, } } + +// NewDiscardFilePutter is a bit bucket FilePutter +func NewDiscardFilePutter() FilePutter { + return &bitBucketFilePutter{} +} + +type bitBucketFilePutter struct { +} + +func (bbfp *bitBucketFilePutter) Put(name string, r io.Reader) error { + _, err := io.Copy(ioutil.Discard, r) + return err +} diff --git a/tar/asm/getter_test.go b/tar/asm/getter_test.go index 4206189..9adb171 100644 --- a/tar/asm/getter_test.go +++ b/tar/asm/getter_test.go @@ -31,3 +31,17 @@ func TestGetter(t *testing.T) { } } } +func TestPutter(t *testing.T) { + fp := NewDiscardFilePutter() + files := map[string][]byte{ + "file1.txt": []byte("foo"), + "file2.txt": []byte("bar"), + "file3.txt": []byte("baz"), + "file4.txt": []byte("bif"), + } + for n, b := range files { + if err := fp.Put(n, bytes.NewBuffer(b)); err != nil { + t.Error(err) + } + } +}