1package archiver 2 3import ( 4 "fmt" 5 "io" 6 "strings" 7 8 "github.com/dsnet/compress/bzip2" 9) 10 11// TarBz2 facilitates bzip2 compression 12// (https://github.com/dsnet/compress/blob/master/doc/bzip2-format.pdf) 13// of tarball archives. 14type TarBz2 struct { 15 *Tar 16 17 CompressionLevel int 18} 19 20// CheckExt ensures the file extension matches the format. 21func (*TarBz2) CheckExt(filename string) error { 22 if !strings.HasSuffix(filename, ".tar.bz2") && 23 !strings.HasSuffix(filename, ".tbz2") { 24 return fmt.Errorf("filename must have a .tar.bz2 or .tbz2 extension") 25 } 26 return nil 27} 28 29// Archive creates a compressed tar file at destination 30// containing the files listed in sources. The destination 31// must end with ".tar.bz2" or ".tbz2". File paths can be 32// those of regular files or directories; directories will 33// be recursively added. 34func (tbz2 *TarBz2) Archive(sources []string, destination string) error { 35 err := tbz2.CheckExt(destination) 36 if err != nil { 37 return fmt.Errorf("output %s", err.Error()) 38 } 39 tbz2.wrapWriter() 40 return tbz2.Tar.Archive(sources, destination) 41} 42 43// Unarchive unpacks the compressed tarball at 44// source to destination. Destination will be 45// treated as a folder name. 46func (tbz2 *TarBz2) Unarchive(source, destination string) error { 47 tbz2.wrapReader() 48 return tbz2.Tar.Unarchive(source, destination) 49} 50 51// Walk calls walkFn for each visited item in archive. 52func (tbz2 *TarBz2) Walk(archive string, walkFn WalkFunc) error { 53 tbz2.wrapReader() 54 return tbz2.Tar.Walk(archive, walkFn) 55} 56 57// Create opens tbz2 for writing a compressed 58// tar archive to out. 59func (tbz2 *TarBz2) Create(out io.Writer) error { 60 tbz2.wrapWriter() 61 return tbz2.Tar.Create(out) 62} 63 64// Open opens t for reading a compressed archive from 65// in. The size parameter is not used. 66func (tbz2 *TarBz2) Open(in io.Reader, size int64) error { 67 tbz2.wrapReader() 68 return tbz2.Tar.Open(in, size) 69} 70 71// Extract extracts a single file from the tar archive. 72// If the target is a directory, the entire folder will 73// be extracted into destination. 74func (tbz2 *TarBz2) Extract(source, target, destination string) error { 75 tbz2.wrapReader() 76 return tbz2.Tar.Extract(source, target, destination) 77} 78 79func (tbz2 *TarBz2) wrapWriter() { 80 var bz2w *bzip2.Writer 81 tbz2.Tar.writerWrapFn = func(w io.Writer) (io.Writer, error) { 82 var err error 83 bz2w, err = bzip2.NewWriter(w, &bzip2.WriterConfig{ 84 Level: tbz2.CompressionLevel, 85 }) 86 return bz2w, err 87 } 88 tbz2.Tar.cleanupWrapFn = func() { 89 bz2w.Close() 90 } 91} 92 93func (tbz2 *TarBz2) wrapReader() { 94 var bz2r *bzip2.Reader 95 tbz2.Tar.readerWrapFn = func(r io.Reader) (io.Reader, error) { 96 var err error 97 bz2r, err = bzip2.NewReader(r, nil) 98 return bz2r, err 99 } 100 tbz2.Tar.cleanupWrapFn = func() { 101 bz2r.Close() 102 } 103} 104 105func (tbz2 *TarBz2) String() string { return "tar.bz2" } 106 107// NewTarBz2 returns a new, default instance ready to be customized and used. 108func NewTarBz2() *TarBz2 { 109 return &TarBz2{ 110 CompressionLevel: bzip2.DefaultCompression, 111 Tar: NewTar(), 112 } 113} 114 115// Compile-time checks to ensure type implements desired interfaces. 116var ( 117 _ = Reader(new(TarBz2)) 118 _ = Writer(new(TarBz2)) 119 _ = Archiver(new(TarBz2)) 120 _ = Unarchiver(new(TarBz2)) 121 _ = Walker(new(TarBz2)) 122 _ = Extractor(new(TarBz2)) 123) 124 125// DefaultTarBz2 is a convenient archiver ready to use. 126var DefaultTarBz2 = NewTarBz2() 127