Skip to content

Instantly share code, notes, and snippets.

@vbatts
Created October 25, 2016 17:54
Show Gist options
  • Save vbatts/68408f64cd41463316548bd5415a6984 to your computer and use it in GitHub Desktop.
Save vbatts/68408f64cd41463316548bd5415a6984 to your computer and use it in GitHub Desktop.
Use gzip comment field for added info
package main
import (
"compress/gzip"
"crypto/sha256"
"encoding/json"
"flag"
"fmt"
"io"
"log"
"os"
"syscall"
"time"
)
var (
flZip = flag.Bool("zip", false, "compress/deflate the paths provided")
flUnzip = flag.Bool("unzip", false, "uncompress/inflate the paths provided")
flList = flag.Bool("list", false, "list the metadata of compressed files for each of the paths provided")
)
func main() {
flag.Parse()
if *flZip {
if err := Gzip(flag.Args()...); err != nil {
log.Fatal(err)
}
return
}
if *flList {
if err := List(os.Stdout, flag.Args()...); err != nil {
log.Fatal(err)
}
return
}
if *flUnzip {
//
return
}
log.Println("no actions choosen!")
flag.Usage()
os.Exit(1)
}
func List(w io.Writer, filenames ...string) error {
isErr := false
for _, arg := range filenames {
fh, err := os.Open(arg)
if err != nil {
log.Println("ERROR: ", err)
isErr = true
continue
}
defer fh.Close()
gz, err := gzip.NewReader(fh)
if err != nil {
log.Println("ERROR: ", err)
isErr = true
continue
}
attr, err := FromJson(gz.Header.Comment)
if err != nil {
log.Println("ERROR: ", err)
isErr = true
continue
}
defer gz.Close()
fmt.Fprintf(w, "%#v\n", attr)
}
if isErr {
return ErrOccured
}
return nil
}
var ErrOccured = fmt.Errorf("errors occured")
func Gzip(filenames ...string) error {
isErr := false
for _, arg := range filenames {
info, err := os.Lstat(arg)
if err != nil {
log.Println("ERROR: ", err)
isErr = true
continue
}
attr := Attributes{
Name: info.Name(),
Mode: uint32(info.Mode()),
Mtime: info.ModTime(),
}
if stat, ok := info.Sys().(*syscall.Stat_t); ok {
attr.Uid = stat.Uid
attr.Gid = stat.Gid
}
if info.Mode().IsRegular() {
sum, err := Sum(arg)
if err != nil {
log.Println("ERROR: ", err)
isErr = true
continue
}
attr.Checksum = sum
}
comment, err := ToJson(attr)
if err != nil {
log.Println("ERROR: ", err)
isErr = true
continue
}
outputFH, err := os.Create(arg + ".gz")
if err != nil {
log.Println("ERROR: ", err)
isErr = true
continue
}
defer outputFH.Close()
gz := gzip.NewWriter(outputFH)
gz.Header.Comment = comment // has to happen before the first .Write()
defer gz.Close()
inputFH, err := os.Open(arg)
if err != nil {
log.Println("ERROR: ", err)
isErr = true
continue
}
defer inputFH.Close()
if _, err := io.Copy(gz, inputFH); err != nil {
log.Println("ERROR: ", err)
isErr = true
continue
}
}
if isErr {
return ErrOccured
}
return nil
}
type Attributes struct {
Name string
Uid uint32
Gid uint32
Mode uint32
Mtime time.Time
Checksum string
}
func FromJson(s string) (*Attributes, error) {
a := Attributes{}
if err := json.Unmarshal([]byte(s), &a); err != nil {
return nil, err
}
return &a, nil
}
func ToJson(a Attributes) (string, error) {
buf, err := json.Marshal(a)
if err != nil {
return "", err
}
return string(buf), nil
}
func Sum(filename string) (string, error) {
fh, err := os.Open(filename)
if err != nil {
return "", err
}
defer fh.Close()
h := sha256.New()
if _, err = io.Copy(h, fh); err != nil {
return "", err
}
return fmt.Sprintf("sha256:%x", h.Sum(nil)), nil
}
@dsnet
Copy link

dsnet commented Oct 25, 2016

I saw this on Twitter. Note that the comment field is pretty limiting in that it can only hold 511 bytes. See golang/go#14639

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment