From 16d34f33abb42e297c4bd983d6dbd6c9153473aa Mon Sep 17 00:00:00 2001 From: Brandon Gibson Date: Thu, 26 May 2016 03:21:56 -0700 Subject: [PATCH 1/2] add support for symbolic links. targz can extract symlinks, and create. zip merely skips them due to lack of symbolic link support for zip. Chmod on files as well, save windows builds. --- targz.go | 25 ++++++++++++++----------- zip.go | 44 ++++++++++++++++++++++++++++++++++---------- 2 files changed, 48 insertions(+), 21 deletions(-) diff --git a/targz.go b/targz.go index d5c624b5..ebaaa366 100644 --- a/targz.go +++ b/targz.go @@ -76,17 +76,18 @@ func tarGzFile(tarWriter *tar.Writer, source string) error { return nil } - file, err := os.Open(path) - if err != nil { - return fmt.Errorf("%s: open: %v", path, err) + if header.Typeflag == tar.TypeReg { + file, err := os.Open(path) + if err != nil { + return fmt.Errorf("%s: open: %v", path, err) + } + defer file.Close() + + _, err = io.Copy(tarWriter, file) + if err != nil { + return fmt.Errorf("%s: copying contents: %v", path, err) + } } - defer file.Close() - - _, err = io.Copy(tarWriter, file) - if err != nil { - return fmt.Errorf("%s: copying contents: %v", path, err) - } - return nil }) } @@ -128,7 +129,9 @@ func untarGzFile(tr *tar.Reader, header *tar.Header, destination string) error { case tar.TypeDir: return mkdir(filepath.Join(destination, header.Name)) case tar.TypeReg: - return writeNewFile(filepath.Join(destination, header.Name), tr) + return writeNewFile(filepath.Join(destination, header.Name), tr, header.FileInfo().Mode()) + case tar.TypeSymlink: + return writeNewSymbolicLink(filepath.Join(destination, header.Name), header.Linkname) default: return fmt.Errorf("%s: unknown type flag: %c", header.Name, header.Typeflag) } diff --git a/zip.go b/zip.go index 27f80c99..633027f3 100644 --- a/zip.go +++ b/zip.go @@ -8,6 +8,7 @@ import ( "os" "path" "path/filepath" + "runtime" "strings" ) @@ -84,15 +85,17 @@ func zipFile(w *zip.Writer, source string) error { return nil } - file, err := os.Open(fpath) - if err != nil { - return fmt.Errorf("%s: opening: %v", fpath, err) - } - defer file.Close() + if header.Mode().IsRegular() { + file, err := os.Open(fpath) + if err != nil { + return fmt.Errorf("%s: opening: %v", fpath, err) + } + defer file.Close() - _, err = io.Copy(writer, file) - if err != nil { - return fmt.Errorf("%s: copying contents: %v", fpath, err) + _, err = io.Copy(writer, file) + if err != nil { + return fmt.Errorf("%s: copying contents: %v", fpath, err) + } } return nil @@ -127,10 +130,10 @@ func unzipFile(zf *zip.File, destination string) error { } defer rc.Close() - return writeNewFile(filepath.Join(destination, zf.Name), rc) + return writeNewFile(filepath.Join(destination, zf.Name), rc, zf.FileInfo().Mode()) } -func writeNewFile(fpath string, in io.Reader) error { +func writeNewFile(fpath string, in io.Reader, fm os.FileMode) error { err := os.MkdirAll(path.Dir(fpath), 0755) if err != nil { return fmt.Errorf("%s: making directory for file: %v", fpath, err) @@ -142,6 +145,13 @@ func writeNewFile(fpath string, in io.Reader) error { } defer out.Close() + err = out.Chmod(fm) + if err != nil { + if runtime.GOOS != "windows" { + return fmt.Errorf("%s: changing file mode: %v", fpath, err) + } + } + _, err = io.Copy(out, in) if err != nil { return fmt.Errorf("%s: writing file: %v", fpath, err) @@ -149,6 +159,20 @@ func writeNewFile(fpath string, in io.Reader) error { return nil } +func writeNewSymbolicLink(fpath string, target string) error { + err := os.MkdirAll(path.Dir(fpath), 0755) + if err != nil { + return fmt.Errorf("%s: making directory for file: %v", fpath, err) + } + + err = os.Symlink(target, fpath) + if err != nil { + return fmt.Errorf("%s: making symbolic link for: %v", fpath, err) + } + + return nil +} + func mkdir(dirPath string) error { err := os.Mkdir(dirPath, 0755) if err != nil { From e1b068b9ad736d3826e002dac65403f4e4643293 Mon Sep 17 00:00:00 2001 From: Brandon Gibson Date: Mon, 6 Jun 2016 11:24:41 -0700 Subject: [PATCH 2/2] Testing for fileMode persistence & consolidation of if statement. --- zip.go | 6 ++---- zip_test.go | 12 ++++++++++++ 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/zip.go b/zip.go index 633027f3..e78c5203 100644 --- a/zip.go +++ b/zip.go @@ -146,10 +146,8 @@ func writeNewFile(fpath string, in io.Reader, fm os.FileMode) error { defer out.Close() err = out.Chmod(fm) - if err != nil { - if runtime.GOOS != "windows" { - return fmt.Errorf("%s: changing file mode: %v", fpath, err) - } + if err != nil && runtime.GOOS != "windows" { + return fmt.Errorf("%s: changing file mode: %v", fpath, err) } _, err = io.Copy(out, in) diff --git a/zip_test.go b/zip_test.go index 927c8663..3a1aa862 100644 --- a/zip_test.go +++ b/zip_test.go @@ -65,17 +65,29 @@ func symmetricTest(t *testing.T, ext string, cf CompressFunc, dcf DecompressFunc return nil } + expectedFileInfo, err := os.Stat(origPath) + if err != nil { + t.Fatalf("%s: Error obtaining original file info: %v", fpath, err) + } expected, err := ioutil.ReadFile(origPath) if err != nil { t.Fatalf("%s: Couldn't open original file (%s) from disk: %v", fpath, origPath, err) } + actualFileInfo, err := os.Stat(fpath) + if err != nil { + t.Fatalf("%s: Error obtaining actual file info: %v", fpath, err) + } actual, err := ioutil.ReadFile(fpath) if err != nil { t.Fatalf("%s: Couldn't open new file from disk: %v", fpath, err) } + if actualFileInfo.Mode() != expectedFileInfo.Mode() { + t.Fatalf("%s: File mode differed between on disk and compressed", + expectedFileInfo.Mode().String()+" : "+actualFileInfo.Mode().String()) + } if !bytes.Equal(expected, actual) { t.Fatalf("%s: File contents differed between on disk and compressed", origPath) }