1
0
Fork 0
mirror of https://github.com/vbatts/go-mtree.git synced 2024-11-25 09:35:39 +00:00

tar: flatten the pseudo-tree only after readHeaders() is done

Flattening within the readHeaders() function call was problematic
because readHeaders() is called as a goroutine; thus, as the
main program was calling `tdh.writeTo(os.Stdout)`, readHeaders() was
still in the process of flattening the tree structure. To get around this,
we now call flatten in ts.Hierarchy(), such that only when the main program
is ready to retrieve a "valid" DirectoryHierarchy from the archive, should
we flatten the tree.

Signed-off-by: Stephen Chung <schung@redhat.com>
This commit is contained in:
Stephen Chung 2016-08-02 11:42:02 -04:00
parent 822f319224
commit 6a37331074

21
tar.go
View file

@ -2,6 +2,7 @@ package mtree
import ( import (
"archive/tar" "archive/tar"
"fmt"
"io" "io"
"io/ioutil" "io/ioutil"
"os" "os"
@ -29,11 +30,13 @@ func NewTarStreamer(r io.Reader, keywords []string) Streamer {
tarReader: tar.NewReader(pR), tarReader: tar.NewReader(pR),
keywords: keywords, keywords: keywords,
} }
go ts.readHeaders() // I don't like this
go ts.readHeaders()
return ts return ts
} }
type tarStream struct { type tarStream struct {
root *Entry
creator dhCreator creator dhCreator
pipeReader *io.PipeReader pipeReader *io.PipeReader
pipeWriter *io.PipeWriter pipeWriter *io.PipeWriter
@ -50,7 +53,7 @@ func (ts *tarStream) readHeaders() {
Raw: "# .", Raw: "# .",
Type: CommentType, Type: CommentType,
} }
root := Entry{ ts.root = &Entry{
Name: ".", Name: ".",
Type: RelativeType, Type: RelativeType,
Prev: &rootComment, Prev: &rootComment,
@ -67,7 +70,6 @@ func (ts *tarStream) readHeaders() {
for { for {
hdr, err := ts.tarReader.Next() hdr, err := ts.tarReader.Next()
if err != nil { if err != nil {
flatten(&root, &ts.creator, ts.keywords)
ts.pipeReader.CloseWithError(err) ts.pipeReader.CloseWithError(err)
return return
} }
@ -162,12 +164,12 @@ func (ts *tarStream) readHeaders() {
} }
} }
if filepath.Dir(filepath.Clean(hdr.Name)) == "." { if filepath.Dir(filepath.Clean(hdr.Name)) == "." {
root.Set = &s ts.root.Set = &s
} else { } else {
e.Set = &s e.Set = &s
} }
} }
err = populateTree(&root, &e, hdr) err = populateTree(ts.root, &e, hdr)
if err != nil { if err != nil {
ts.setErr(err) ts.setErr(err)
} }
@ -209,6 +211,7 @@ func populateTree(root, e *Entry, hdr *tar.Header) error {
} }
return nil return nil
} }
// TODO: what about directory/file names with "/" in it?
dirNames := strings.Split(wd, "/") dirNames := strings.Split(wd, "/")
parent := root parent := root
for _, name := range dirNames[1:] { for _, name := range dirNames[1:] {
@ -259,6 +262,9 @@ func populateTree(root, e *Entry, hdr *tar.Header) error {
// creator: a dhCreator that helps with the '/set' keyword // creator: a dhCreator that helps with the '/set' keyword
// keywords: keywords specified by the user that should be evaluated // keywords: keywords specified by the user that should be evaluated
func flatten(root *Entry, creator *dhCreator, keywords []string) { func flatten(root *Entry, creator *dhCreator, keywords []string) {
if root == nil {
return
}
if root.Prev != nil { if root.Prev != nil {
// root.Prev != nil implies root is a directory // root.Prev != nil implies root is a directory
creator.DH.Entries = append(creator.DH.Entries, creator.DH.Entries = append(creator.DH.Entries,
@ -317,6 +323,7 @@ func flatten(root *Entry, creator *dhCreator, keywords []string) {
} }
creator.DH.Entries = append(creator.DH.Entries, dotEntry) creator.DH.Entries = append(creator.DH.Entries, dotEntry)
} }
return
} }
// filter takes in a pointer to an Entry, and returns a slice of Entry's that // filter takes in a pointer to an Entry, and returns a slice of Entry's that
@ -387,5 +394,9 @@ func (ts *tarStream) Hierarchy() (*DirectoryHierarchy, error) {
if ts.err != nil && ts.err != io.EOF { if ts.err != nil && ts.err != io.EOF {
return nil, ts.err return nil, ts.err
} }
if ts.root == nil {
return nil, fmt.Errorf("root Entry not found. Nothing to flatten")
}
flatten(ts.root, &ts.creator, ts.keywords)
return ts.creator.DH, nil return ts.creator.DH, nil
} }