From 7ccbb9d40cf1cbdbcf96bbc06da2d1614ee6f5f1 Mon Sep 17 00:00:00 2001 From: Vincent Batts Date: Tue, 24 Feb 2015 17:07:00 -0500 Subject: [PATCH] tar/asm: initial assmebly of tar stream --- tar/asm/README.md | 18 +++++++++++++++ tar/asm/assemble.go | 53 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 tar/asm/README.md create mode 100644 tar/asm/assemble.go diff --git a/tar/asm/README.md b/tar/asm/README.md new file mode 100644 index 0000000..dd9d1e8 --- /dev/null +++ b/tar/asm/README.md @@ -0,0 +1,18 @@ +asm +=== + +This library for assembly and disassembly of tar archives, facilitated by +`github.com/vbatts/tar-split/tar/storage`. + + + +Thoughts +-------- + +While the initial implementation is based on a relative path, I'm thinking the +next step is to have something like a FileGetter interface, of which a path +based getter is just one type. + +Then you could pass a path based Getter and an Unpacker, and receive a +io.Reader that is your tar stream. + diff --git a/tar/asm/assemble.go b/tar/asm/assemble.go new file mode 100644 index 0000000..7f87bc3 --- /dev/null +++ b/tar/asm/assemble.go @@ -0,0 +1,53 @@ +package asm + +import ( + "io" + "os" + "path" + + "github.com/vbatts/tar-split/tar/storage" +) + +func NewTarStream(relpath string, up storage.Unpacker) io.ReadCloser { + pr, pw := io.Pipe() + go func() { + for { + entry, err := up.Next() + if err != nil { + pw.CloseWithError(err) + break + } + switch entry.Type { + case storage.SegmentType: + if _, err := pw.Write(entry.Payload); err != nil { + pw.CloseWithError(err) + break + } + case storage.FileType: + if err := writeEntryFromRelPath(pw, relpath, entry); err != nil { + pw.CloseWithError(err) + break + } + } + } + }() + 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 +}