Skip to content

Commit

Permalink
Add support for prefixed bytes to zipper
Browse files Browse the repository at this point in the history
See #411 (comment)
for background.

[#93671532]

Signed-off-by: Kris Hicks <khicks@pivotal.io>
  • Loading branch information
Simon Leung authored and Kris Hicks committed Nov 19, 2015
1 parent 2654a47 commit 3cd710b
Show file tree
Hide file tree
Showing 2 changed files with 308 additions and 48 deletions.
195 changes: 159 additions & 36 deletions cf/app_files/zipper.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package app_files

import (
"archive/zip"
"bufio"
"bytes"
"io"
"os"
"path/filepath"
Expand Down Expand Up @@ -29,11 +31,91 @@ func (zipper ApplicationZipper) Zip(dirOrZipFile string, targetFile *os.File) (e
return
}

func (zipper ApplicationZipper) IsZipFile(file string) (result bool) {
_, err := zip.OpenReader(file)
func (zipper ApplicationZipper) IsZipFile(name string) bool {
f, err := os.Open(name)
if err != nil {
return false
}

fi, err := f.Stat()
if err != nil {
return false
}

if fi.IsDir() {
return false
}

_, err = zip.OpenReader(name)
if err != nil && err == zip.ErrFormat {
return zipper.isZipWithOffsetFileHeaderLocation(name)
}

return err == nil
}

func (zipper ApplicationZipper) Unzip(name string, destDir string) error {
rc, err := zip.OpenReader(name)

if err == nil {
defer rc.Close()
for _, f := range rc.File {
err := zipper.extractFile(f, destDir)
if err != nil {
return err
}
}
}

if err == zip.ErrFormat {
loc, err := zipper.zipFileHeaderLocation(name)
if err != nil {
return err
}

if loc > int64(-1) {
f, err := os.Open(name)
if err != nil {
return err
}

defer f.Close()

fi, err := f.Stat()
if err != nil {
return err
}

readerAt := io.NewSectionReader(f, loc, fi.Size())
r, err := zip.NewReader(readerAt, fi.Size())
if err != nil {
return err
}
for _, f := range r.File {
err := zipper.extractFile(f, destDir)
if err != nil {
return err
}
}
}
}

return nil
}

func (zipper ApplicationZipper) GetZipSize(zipFile *os.File) (int64, error) {
zipFileSize := int64(0)

stat, err := zipFile.Stat()
if err != nil {
return 0, err
}

zipFileSize = int64(stat.Size())

return zipFileSize, nil
}

func writeZipFile(dir string, targetFile *os.File) error {
isEmpty, err := fileutils.IsDirEmpty(dir)
if err != nil {
Expand Down Expand Up @@ -78,61 +160,102 @@ func writeZipFile(dir string, targetFile *os.File) error {
})
}

func (zipper ApplicationZipper) Unzip(appDir string, destDir string) error {
r, err := zip.OpenReader(appDir)
func (zipper ApplicationZipper) zipFileHeaderLocation(name string) (int64, error) {
f, err := os.Open(name)
if err != nil {
return err
return -1, err
}
defer r.Close()

for _, f := range r.File {
// anonymous func allows the defer of rc.Close()
err = func() error {
if f.FileInfo().IsDir() {
os.MkdirAll(filepath.Join(destDir, f.Name), os.ModeDir|os.ModePerm)
return nil
}
defer f.Close()

var rc io.ReadCloser
rc, err = f.Open()
if err != nil {
return err
}
// zip file header signature, 0x04034b50, reversed due to little-endian byte order
firstByte := byte(0x50)
restBytes := []byte{0x4b, 0x03, 0x04}
count := int64(-1)
foundAt := int64(-1)

defer rc.Close()
reader := bufio.NewReader(f)

destFilePath := filepath.Join(destDir, f.Name)
keepGoing := true
for keepGoing {
count++

err = fileutils.CopyReaderToPath(rc, destFilePath)
if err != nil {
return err
}
b, err := reader.ReadByte()
if err != nil {
keepGoing = false
break
}

err = os.Chmod(destFilePath, f.FileInfo().Mode())
if b == firstByte {
nextBytes, err := reader.Peek(3)
if err != nil {
return err
keepGoing = false
}
if bytes.Compare(nextBytes, restBytes) == 0 {
foundAt = count
keepGoing = false
break
}
}
}

return nil
}()
return foundAt, nil
}

func (zipper ApplicationZipper) isZipWithOffsetFileHeaderLocation(name string) bool {
loc, err := zipper.zipFileHeaderLocation(name)
if err != nil {
return false
}

if loc > int64(-1) {
f, err := os.Open(name)
if err != nil {
return err
return false
}

defer f.Close()

fi, err := f.Stat()
if err != nil {
return false
}

readerAt := io.NewSectionReader(f, loc, fi.Size())
_, err = zip.NewReader(readerAt, fi.Size())
if err == nil {
return true
}
}

return nil
return false
}

func (zipper ApplicationZipper) GetZipSize(zipFile *os.File) (int64, error) {
zipFileSize := int64(0)
func (zipper ApplicationZipper) extractFile(f *zip.File, destDir string) error {
if f.FileInfo().IsDir() {
os.MkdirAll(filepath.Join(destDir, f.Name), os.ModeDir|os.ModePerm)
return nil
}

stat, err := zipFile.Stat()
var rc io.ReadCloser
rc, err := f.Open()
if err != nil {
return 0, err
return err
}

zipFileSize = int64(stat.Size())
defer rc.Close()

return zipFileSize, nil
destFilePath := filepath.Join(destDir, f.Name)

err = fileutils.CopyReaderToPath(rc, destFilePath)
if err != nil {
return err
}

err = os.Chmod(destFilePath, f.FileInfo().Mode())
if err != nil {
return err
}

return nil
}
Loading

0 comments on commit 3cd710b

Please sign in to comment.