Created
October 25, 2016 17:54
-
-
Save vbatts/68408f64cd41463316548bd5415a6984 to your computer and use it in GitHub Desktop.
Use gzip comment field for added info
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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