diff --git a/tar/asm/README.md b/tar/asm/README.md index dd9d1e8..c848830 100644 --- a/tar/asm/README.md +++ b/tar/asm/README.md @@ -5,6 +5,21 @@ This library for assembly and disassembly of tar archives, facilitated by `github.com/vbatts/tar-split/tar/storage`. +Concerns +-------- + +For completely safe assembly/disassembly, there will need to be a CAS +directory, that maps to a checksum in the `storage.Entity` of +`storage.FileType`. + +This is due to the fact that tar archives _can_ allow multiple records for the +same path, but the last one effectively wins. Even if the prior records had a +different payload. + +In this way, when assembling an archive from relative paths, if the archive has +multiple entries for the same path, then all payloads read in from a relative +path would be identical. + Thoughts -------- diff --git a/tar/asm/assemble.go b/tar/asm/assemble.go index 7f87bc3..41fafc2 100644 --- a/tar/asm/assemble.go +++ b/tar/asm/assemble.go @@ -2,13 +2,11 @@ package asm import ( "io" - "os" - "path" "github.com/vbatts/tar-split/tar/storage" ) -func NewTarStream(relpath string, up storage.Unpacker) io.ReadCloser { +func NewTarStream(fg FileGetter, up storage.Unpacker) io.ReadCloser { pr, pw := io.Pipe() go func() { for { @@ -24,7 +22,16 @@ func NewTarStream(relpath string, up storage.Unpacker) io.ReadCloser { break } case storage.FileType: - if err := writeEntryFromRelPath(pw, relpath, entry); err != nil { + if entry.Size == 0 { + continue + } + fh, err := fg.Get(entry.Name) + if err != nil { + pw.CloseWithError(err) + break + } + defer fh.Close() + if _, err := io.Copy(pw, fh); err != nil { pw.CloseWithError(err) break } @@ -33,21 +40,3 @@ func NewTarStream(relpath string, up storage.Unpacker) io.ReadCloser { }() return pr } - -func writeEntryFromRelPath(w io.Writer, root string, entry *storage.Entry) error { - if entry.Size == 0 { - return nil - } - - // FIXME might should have a check for '../../../../etc/passwd' attempts? - fh, err := os.Open(path.Join(root, entry.Name)) - if err != nil { - return err - } - defer fh.Close() - if _, err := io.Copy(w, fh); err != nil { - return err - } - - return nil -} diff --git a/tar/asm/getter.go b/tar/asm/getter.go new file mode 100644 index 0000000..c875d94 --- /dev/null +++ b/tar/asm/getter.go @@ -0,0 +1,26 @@ +package asm + +import ( + "io" + "os" + "path" +) + +type FileGetter interface { + // Get returns a stream for the provided file path + Get(string) (io.ReadCloser, error) +} + +// NewPathFileGetter returns a FileGetter that is for files relative to path relpath. +func NewPathFileGetter(relpath string) FileGetter { + return &pathFileGetter{root: relpath} +} + +type pathFileGetter struct { + root string +} + +func (pfg pathFileGetter) Get(filename string) (io.ReadCloser, error) { + // FIXME might should have a check for '../../../../etc/passwd' attempts? + return os.Open(path.Join(pfg.root, filename)) +}