diff --git a/cmd/stbak/cmd/archive.go b/cmd/stbak/cmd/archive.go index be1cb9f..240abdb 100644 --- a/cmd/stbak/cmd/archive.go +++ b/cmd/stbak/cmd/archive.go @@ -11,6 +11,7 @@ import ( "strconv" "github.com/andybalholm/brotli" + "github.com/dsnet/compress/bzip2" "github.com/klauspost/compress/zstd" "github.com/klauspost/pgzip" "github.com/pierrec/lz4/v4" @@ -326,6 +327,40 @@ func archive( hdr.Size = int64(fileSizeCounter.BytesRead) hdr.Name += compressionFormatBrotliSuffix + case compressionFormatBzip2Key: + // Get the compressed size for the header + file, err := os.Open(path) + if err != nil { + return err + } + + fileSizeCounter := counters.CounterWriter{ + Writer: io.Discard, + } + + bz, err := bzip2.NewWriter(&fileSizeCounter, nil) + if err != nil { + return err + } + + if _, err := io.Copy(bz, file); err != nil { + return err + } + + if err := bz.Close(); err != nil { + return err + } + if err := file.Close(); err != nil { + return err + } + + if hdr.PAXRecords == nil { + hdr.PAXRecords = map[string]string{} + } + hdr.PAXRecords[pax.STFSRecordUncompressedSize] = strconv.Itoa(int(hdr.Size)) + hdr.Size = int64(fileSizeCounter.BytesRead) + + hdr.Name += compressionFormatBzip2Suffix case compressionFormatNoneKey: default: return errUnsupportedCompressionFormat @@ -494,6 +529,39 @@ func archive( if err := file.Close(); err != nil { return err } + case compressionFormatBzip2Key: + // Compress and write the file + file, err := os.Open(path) + if err != nil { + return err + } + + lz, err := bzip2.NewWriter(tw, nil) + if err != nil { + return err + } + + if _, err := io.Copy(lz, file); err != nil { + return err + } + + if isRegular { + if _, err := io.Copy(lz, file); err != nil { + return err + } + } else { + buf := make([]byte, controllers.BlockSize*recordSize) + if _, err := io.CopyBuffer(lz, file, buf); err != nil { + return err + } + } + + if err := lz.Close(); err != nil { + return err + } + if err := file.Close(); err != nil { + return err + } case compressionFormatNoneKey: // Write the file file, err := os.Open(path) diff --git a/cmd/stbak/cmd/recovery_fetch.go b/cmd/stbak/cmd/recovery_fetch.go index 8fdfd99..8683439 100644 --- a/cmd/stbak/cmd/recovery_fetch.go +++ b/cmd/stbak/cmd/recovery_fetch.go @@ -9,6 +9,7 @@ import ( "path/filepath" "github.com/andybalholm/brotli" + "github.com/dsnet/compress/bzip2" "github.com/klauspost/compress/zstd" "github.com/klauspost/pgzip" "github.com/pierrec/lz4/v4" @@ -177,6 +178,15 @@ func restoreFromRecordAndBlock( if _, err := io.Copy(dstFile, br); err != nil { return err } + case compressionFormatBzip2Key: + bz, err := bzip2.NewReader(tr, nil) + if err != nil { + return err + } + + if _, err := io.Copy(dstFile, bz); err != nil { + return err + } case compressionFormatNoneKey: if _, err := io.Copy(dstFile, tr); err != nil { return err diff --git a/cmd/stbak/cmd/recovery_index.go b/cmd/stbak/cmd/recovery_index.go index 0a77e21..606bec0 100644 --- a/cmd/stbak/cmd/recovery_index.go +++ b/cmd/stbak/cmd/recovery_index.go @@ -279,6 +279,8 @@ func indexHeader( hdr.Name = strings.TrimSuffix(hdr.Name, compressionFormatZStandardSuffix) case compressionFormatBrotliKey: hdr.Name = strings.TrimSuffix(hdr.Name, compressionFormatBrotliSuffix) + case compressionFormatBzip2Key: + hdr.Name = strings.TrimSuffix(hdr.Name, compressionFormatBzip2Suffix) case compressionFormatNoneKey: default: return errUnsupportedCompressionFormat diff --git a/cmd/stbak/cmd/root.go b/cmd/stbak/cmd/root.go index e1160eb..36c9c48 100644 --- a/cmd/stbak/cmd/root.go +++ b/cmd/stbak/cmd/root.go @@ -32,10 +32,13 @@ const ( compressionFormatBrotliKey = "brotli" compressionFormatBrotliSuffix = ".br" + + compressionFormatBzip2Key = "bzip2" + compressionFormatBzip2Suffix = ".bz2" ) var ( - knownCompressionFormats = []string{compressionFormatNoneKey, compressionFormatGZipKey, compressionFormatParallelGZipKey, compressionFormatLZ4Key, compressionFormatZStandardKey, compressionFormatBrotliKey} + knownCompressionFormats = []string{compressionFormatNoneKey, compressionFormatGZipKey, compressionFormatParallelGZipKey, compressionFormatLZ4Key, compressionFormatZStandardKey, compressionFormatBrotliKey, compressionFormatBzip2Key} errUnknownCompressionFormat = errors.New("unknown compression format") errUnsupportedCompressionFormat = errors.New("unsupported compression format") diff --git a/go.mod b/go.mod index 3f3a2a7..50e714a 100644 --- a/go.mod +++ b/go.mod @@ -19,6 +19,7 @@ require ( require ( github.com/andybalholm/brotli v1.0.4 // indirect + github.com/dsnet/compress v0.0.1 // indirect github.com/fsnotify/fsnotify v1.5.1 // indirect github.com/gofrs/uuid v3.2.0+incompatible // indirect github.com/hashicorp/hcl v1.0.0 // indirect diff --git a/go.sum b/go.sum index 60cf68f..bd13d5c 100644 --- a/go.sum +++ b/go.sum @@ -92,6 +92,9 @@ github.com/denisenkom/go-mssqldb v0.9.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27N github.com/denisenkom/go-mssqldb v0.10.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/dsnet/compress v0.0.1 h1:PlZu0n3Tuv04TzpfPbrnI0HW/YwodEXDS+oPKahKF0Q= +github.com/dsnet/compress v0.0.1/go.mod h1:Aw8dCMJ7RioblQeTqt88akK31OvO8Dhf5JflhBbQEHo= +github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -257,8 +260,10 @@ github.com/kat-co/vala v0.0.0-20170210184112-42e1d8b61f12/go.mod h1:u9MdXq/QageO github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE= github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -402,6 +407,7 @@ github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8= github.com/volatiletech/inflect v0.0.1 h1:2a6FcMQyhmPZcLa+uet3VJ8gLn/9svWhJxJYwvE8KsU= github.com/volatiletech/inflect v0.0.1/go.mod h1:IBti31tG6phkHitLlr5j7shC5SOo//x0AjDzaJU1PLA= github.com/volatiletech/null/v8 v8.1.2 h1:kiTiX1PpwvuugKwfvUNX/SU/5A2KGZMXfGD0DUHdKEI=