github.com/keltia/go-ipfs@v0.3.8-0.20150909044612-210793031c63/unixfs/archive/tar/writer.go (about) 1 package tar 2 3 import ( 4 "archive/tar" 5 "io" 6 "path" 7 "time" 8 9 proto "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/proto" 10 cxt "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" 11 12 mdag "github.com/ipfs/go-ipfs/merkledag" 13 ft "github.com/ipfs/go-ipfs/unixfs" 14 uio "github.com/ipfs/go-ipfs/unixfs/io" 15 upb "github.com/ipfs/go-ipfs/unixfs/pb" 16 ) 17 18 // Writer is a utility structure that helps to write 19 // unixfs merkledag nodes as a tar archive format. 20 // It wraps any io.Writer. 21 type Writer struct { 22 Dag mdag.DAGService 23 TarW *tar.Writer 24 25 ctx cxt.Context 26 } 27 28 // NewWriter wraps given io.Writer. 29 func NewWriter(ctx cxt.Context, dag mdag.DAGService, archive bool, compression int, w io.Writer) (*Writer, error) { 30 return &Writer{ 31 Dag: dag, 32 TarW: tar.NewWriter(w), 33 ctx: ctx, 34 }, nil 35 } 36 37 func (w *Writer) writeDir(nd *mdag.Node, fpath string) error { 38 if err := writeDirHeader(w.TarW, fpath); err != nil { 39 return err 40 } 41 42 for i, ng := range w.Dag.GetDAG(w.ctx, nd) { 43 child, err := ng.Get(w.ctx) 44 if err != nil { 45 return err 46 } 47 48 npath := path.Join(fpath, nd.Links[i].Name) 49 if err := w.WriteNode(child, npath); err != nil { 50 return err 51 } 52 } 53 54 return nil 55 } 56 57 func (w *Writer) writeFile(nd *mdag.Node, pb *upb.Data, fpath string) error { 58 if err := writeFileHeader(w.TarW, fpath, pb.GetFilesize()); err != nil { 59 return err 60 } 61 62 dagr := uio.NewDataFileReader(w.ctx, nd, pb, w.Dag) 63 _, err := dagr.WriteTo(w.TarW) 64 return err 65 } 66 67 func (w *Writer) WriteNode(nd *mdag.Node, fpath string) error { 68 pb := new(upb.Data) 69 if err := proto.Unmarshal(nd.Data, pb); err != nil { 70 return err 71 } 72 73 switch pb.GetType() { 74 case upb.Data_Metadata: 75 fallthrough 76 case upb.Data_Directory: 77 return w.writeDir(nd, fpath) 78 case upb.Data_Raw: 79 fallthrough 80 case upb.Data_File: 81 return w.writeFile(nd, pb, fpath) 82 case upb.Data_Symlink: 83 return writeSymlinkHeader(w.TarW, string(pb.GetData()), fpath) 84 default: 85 return ft.ErrUnrecognizedType 86 } 87 } 88 89 func (w *Writer) Close() error { 90 return w.TarW.Close() 91 } 92 93 func writeDirHeader(w *tar.Writer, fpath string) error { 94 return w.WriteHeader(&tar.Header{ 95 Name: fpath, 96 Typeflag: tar.TypeDir, 97 Mode: 0777, 98 ModTime: time.Now(), 99 // TODO: set mode, dates, etc. when added to unixFS 100 }) 101 } 102 103 func writeFileHeader(w *tar.Writer, fpath string, size uint64) error { 104 return w.WriteHeader(&tar.Header{ 105 Name: fpath, 106 Size: int64(size), 107 Typeflag: tar.TypeReg, 108 Mode: 0644, 109 ModTime: time.Now(), 110 // TODO: set mode, dates, etc. when added to unixFS 111 }) 112 } 113 114 func writeSymlinkHeader(w *tar.Writer, target, fpath string) error { 115 return w.WriteHeader(&tar.Header{ 116 Name: fpath, 117 Linkname: target, 118 Mode: 0777, 119 Typeflag: tar.TypeSymlink, 120 }) 121 }