This code tries to tar some texts into a tar
file and untar it. The code for tar
works but seems like I am doing something wrong because untar
the same file does not work.
When I untar the file that I manually tar.gz with OS GUI, it works but not in this code.
http://play.golang.org/p/diTOojUuBX
func main() {
mpath := "a.tar.gz"
// defer os.Remove(mpath)
f, err := overwrite(mpath)
defer f.Close()
if err != nil {
panic(err)
}
gw := gzip.NewWriter(f)
defer gw.Close()
if err != nil {
panic(err)
}
tw := tar.NewWriter(gw)
for _, file := range files {
hdr := &tar.Header{
Name: file.Name,
Mode: 0600,
Size: int64(len(file.Body)),
}
if err := tw.WriteHeader(hdr); err != nil {
panic(err)
}
if _, err := tw.Write([]byte(file.Body)); err != nil {
panic(err)
}
}
// Make sure to check the error on Close.
if err := tw.Close(); err != nil {
panic(err)
}
fr, err := read(mpath)
defer fr.Close()
if err != nil {
panic(err)
}
gr, err := gzip.NewReader(fr)
defer gr.Close()
if err != nil {
panic(err)
}
tr := tar.NewReader(gr)
for {
hdr, err := tr.Next()
if err == io.EOF {
// end of tar archive
break
}
if err != nil {
panic(err)
}
path := hdr.Name
switch hdr.Typeflag {
case tar.TypeDir:
if err := os.MkdirAll(path, os.FileMode(hdr.Mode)); err != nil {
panic(err)
}
case tar.TypeReg:
ow, err := overwrite(path)
defer ow.Close()
if err != nil {
panic(err)
}
if _, err := io.Copy(ow, tr); err != nil {
panic(err)
}
default:
fmt.Printf("Can't: %c, %s
", hdr.Typeflag, path)
}
}
}
It looks to me like there are two problems.
You are using defer to close your tar writer and gzip writer, however defers only execute when the current scope ends. Since you are running this all in one function your file handles will still be open when you attempt to read to untar and that may cause issues (perhaps file has not flushed fully for example).
You are not setting the Typeflag
in the header when you create the tarball. While GNU tar may deal with this, assuming Typeflag '0', Go may not. According to the docs http://www.gnu.org/software/tar/manual/html_node/Standard.html the Typeflag for a regular file is byte '0'. This may mean you need to set the Typeflag on a per resource in your code (directories, files, links, etc).
I rewrote you code like the following, and it is working for me now. (note: storing everything as REGTYPE)
http://play.golang.org/p/3B7F_axr-i
EDIT
Ah-ha, I know the problem with #2 now. The Go library for tar uses FileInfoHeader in order to determine parts of the header, like Typeflag. Since your files are not really files on the system it cannot fill out the appropriate Typeflag.
GNU tar obviously knows how to deal with this, or perhaps tries its best to figure it out and is successful in this case.