// zipExeReaderPe treats the file as a Portable Exectuable binary
// (Windows executable) and attempts to find a zip archive.
321074
func zipExeReaderPe(rda io.ReaderAt, size int64) (*zip.Reader, error) {
	file, err := pe.NewFile(rda)
	if err != nil {
		return nil, err
	}

	var max int64
	for _, sec := range file.Sections {
		// Check if this section has a zip file
		if zfile, err := zip.NewReader(sec, int64(sec.Size)); err == nil {
			return zfile, nil
		}

		// Otherwise move end of file pointer
		end := int64(sec.Offset + sec.Size)
		if end > max {
			max = end
		}
	}

	// No zip file within binary, try appended to end
	section := io.NewSectionReader(rda, max, size-max)
	return zip.NewReader(section, section.Size())
}
854425
func (zh *zipHandler) blobsFromDir(dirPath string, dirBlob blob.Ref) ([]*blobFile, error) {
	var list []*blobFile
	dr, err := schema.NewDirReader(context.TODO(), zh.fetcher, dirBlob)
	if err != nil {
		return nil, fmt.Errorf("Could not read dir blob %v: %v", dirBlob, err)
	}
	ent, err := dr.Readdir(context.TODO(), -1)
	if err != nil {
		return nil, fmt.Errorf("Could not read dir entries: %v", err)
	}
	for _, v := range ent {
		fullpath := path.Join(dirPath, v.FileName())
		switch v.CamliType() {
		case "file":
			list = append(list, &blobFile{v.BlobRef(), fullpath})
		case "directory":
			children, err := zh.blobsFromDir(fullpath, v.BlobRef())
			if err != nil {
				return nil, fmt.Errorf("Could not get list of blobs from %v: %v", v.BlobRef(), err)
			}
			list = append(list, children...)
		}
	}
	return list, nil
}
452890
func (pk *packer) writeAZip(ctx context.Context, trunc blob.Ref) (err error) {
	defer func() {
		if e := recover(); e != nil {
			if v, ok := e.(error); ok && err == nil {
				err = v
			} else {
				panic(e)
			}
		}
	}()
	mf := Manifest{
		WholeRef:       pk.wholeRef,
		WholeSize:      pk.wholeSize,
		WholePartIndex: len(pk.zips),
	}
	var zbuf bytes.Buffer
	cw := &countWriter{w: &zbuf}
	zw := zip.NewWriter(cw)

	var approxSize = zipFixedOverhead // can't use zbuf.Len because zw buffers
	var dataRefsWritten []blob.Ref
	var dataBytesWritten int64
	var schemaBlobSeen = map[blob.Ref]bool{}
	var schemaBlobs []blob.Ref // to add after the main file

	baseFileName := pk.fr.FileName()
	if strings.Contains(baseFileName, "/") || strings.Contains(baseFileName, "\\") {
		return fmt.Errorf("File schema blob %v filename had a slash in it: %q", pk.fr.SchemaBlobRef(), baseFileName)
	}
	fh := &zip.FileHeader{
		Name:   baseFileName,
		Method: zip.Store, // uncompressed
	}
	fh.SetModTime(pk.fr.ModTime())
	fh.SetMode(0644)
	fw, err := zw.CreateHeader(fh)
	check(err)
	check(zw.Flush())
	dataStart := cw.n
	approxSize += zipPerEntryOverhead // for the first FileHeader w/ the data

	zipMax := pk.s.maxZipBlobSize()
	chunks := pk.chunksRemain
	chunkWholeHash := blob.NewHash()
	for len(chunks) > 0 {
		dr := chunks[0] // the next chunk to maybe write

		if trunc.Valid() && trunc == dr {
			if approxSize == 0 {
				return errors.New("first blob is too large to pack, once you add the zip overhead")
			}
			break
		}

		schemaBlobsSave := schemaBlobs
		for _, parent := range pk.schemaParent[dr] {
			if !schemaBlobSeen[parent] {
				schemaBlobSeen[parent] = true
				schemaBlobs = append(schemaBlobs, parent)
				approxSize += int(pk.schemaBlob[parent].Size()) + zipPerEntryOverhead
			}
		}

		thisSize := pk.dataSize[dr]
		approxSize += int(thisSize)
		if approxSize+mf.approxSerializedSize() > zipMax {
			if fn := testHookStopBeforeOverflowing; fn != nil {
				fn()
			}
			schemaBlobs = schemaBlobsSave // restore it
			break
		}

		// Copy the data to the zip.
		rc, size, err := pk.s.Fetch(ctx, dr)
		check(err)
		if size != thisSize {
			rc.Close()
			return errors.New("unexpected size")
		}
		if n, err := io.Copy(io.MultiWriter(fw, chunkWholeHash), rc); err != nil || n != int64(size) {
			rc.Close()
			return fmt.Errorf("copy to zip = %v, %v; want %v bytes", n, err, size)
		}
		rc.Close()

		dataRefsWritten = append(dataRefsWritten, dr)
		dataBytesWritten += int64(size)
		chunks = chunks[1:]
	}
	mf.DataBlobsOrigin = blob.RefFromHash(chunkWholeHash)

	// zipBlobs is where a schema or data blob is relative to the beginning
	// of the zip file.
	var zipBlobs []BlobAndPos

	var dataOffset int64
	for _, br := range dataRefsWritten {
		size := pk.dataSize[br]
		mf.DataBlobs = append(mf.DataBlobs, BlobAndPos{blob.SizedRef{Ref: br, Size: size}, dataOffset})

		zipBlobs = append(zipBlobs, BlobAndPos{blob.SizedRef{Ref: br, Size: size}, dataStart + dataOffset})
		dataOffset += int64(size)
	}

	for _, br := range schemaBlobs {
		fw, err := zw.CreateHeader(&zip.FileHeader{
			Name:   "camlistore/" + br.String() + ".json",
			Method: zip.Store, // uncompressed
		})
		check(err)
		check(zw.Flush())
		b := pk.schemaBlob[br]
		zipBlobs = append(zipBlobs, BlobAndPos{blob.SizedRef{Ref: br, Size: b.Size()}, cw.n})
		r, err := b.ReadAll(ctx)
		if err != nil {
			return err
		}
		n, err := io.Copy(fw, r)

		check(err)
		if n != int64(b.Size()) {
			return fmt.Errorf("failed to write all of schema blob %v: %d bytes, not wanted %d", br, n, b.Size())
		}
	}

	// Manifest file
	fw, err = zw.Create(zipManifestPath)
	check(err)
	enc, err := json.MarshalIndent(mf, "", "  ")
	check(err)
	_, err = fw.Write(enc)
	check(err)
	err = zw.Close()
	check(err)

	if zbuf.Len() > zipMax {
		// We guessed wrong. Back up. Find out how many blobs we went over.
		overage := zbuf.Len() - zipMax
		for i := len(dataRefsWritten) - 1; i >= 0; i-- {
			dr := dataRefsWritten[i]
			if overage <= 0 {
				return needsTruncatedAfterError{dr}
			}
			overage -= int(pk.dataSize[dr])
		}
		return errors.New("file is unpackable; first blob is too big to fit")
	}

	zipRef := blob.RefFromBytes(zbuf.Bytes())
	zipSB, err := blobserver.ReceiveNoHash(ctx, pk.s.large, zipRef, bytes.NewReader(zbuf.Bytes()))
	if err != nil {
		return err
	}

	bm := pk.s.meta.BeginBatch()
	bm.Set(fmt.Sprintf("%s%s:%d", wholeMetaPrefix, pk.wholeRef, len(pk.zips)),
		fmt.Sprintf("%s %d %d %d",
			zipRef,
			dataStart,
			pk.wholeBytesWritten,
			dataBytesWritten))
	bm.Set(fmt.Sprintf("%s%v", zipMetaPrefix, zipRef),
		fmt.Sprintf("%d %v %d %d %d",
			zipSB.Size,
			pk.wholeRef,
			pk.wholeSize,
			pk.wholeBytesWritten,
			dataBytesWritten))

	pk.wholeBytesWritten += dataBytesWritten
	pk.zips = append(pk.zips, writtenZip{
		SizedRef: zipSB,
		dataRefs: dataRefsWritten,
	})

	for _, zb := range zipBlobs {
		bm.Set(blobMetaPrefix+zb.Ref.String(), fmt.Sprintf("%d %v %d", zb.Size, zipRef, zb.Offset))
	}
	if err := pk.s.meta.CommitBatch(bm); err != nil {
		return err
	}

	// Delete from small
	if !pk.s.skipDelete {
		toDelete := make([]blob.Ref, 0, len(dataRefsWritten)+len(schemaBlobs))
		toDelete = append(toDelete, dataRefsWritten...)
		toDelete = append(toDelete, schemaBlobs...)
		if err := pk.s.small.RemoveBlobs(ctx, toDelete); err != nil {
			// Can't really do anything about it and doesn't really matter, so
			// just log for now.
			pk.s.Logf("Error removing blobs from %s: %v", pk.s.small, err)
		}
	}

	// On success, consume the chunks we wrote from pk.chunksRemain.
	pk.chunksRemain = pk.chunksRemain[len(dataRefsWritten):]
	return nil
}
1029375
func ExecutableFolder() (string, error) {
	p, err := Executable()
	if err != nil {
		return "", err
	}

	return filepath.Dir(p), nil
}
931246
func (dh *DownloadHandler) serveZip(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	if r.Method != "POST" {
		http.Error(w, "Invalid download method", http.StatusBadRequest)
		return
	}

	filesValue := r.FormValue("files")
	if filesValue == "" {
		http.Error(w, "No file blobRefs specified", http.StatusBadRequest)
		return
	}
	files := strings.Split(filesValue, ",")

	var refs []blob.Ref
	for _, file := range files {
		br, ok := blob.Parse(file)
		if !ok {
			http.Error(w, fmt.Sprintf("%q is not a valid blobRef", file), http.StatusBadRequest)
			return
		}
		refs = append(refs, br)
	}

	// We check as many things as we can before writing the zip, because
	// once we start sending a response we can't http.Error anymore.
	var allRefs map[blob.Ref]string
	_, ok := (dh.Fetcher).(*cacher.CachingFetcher)
	if ok {
		// If we have a caching fetcher, allRefs and dh.pathByRef are populated with all
		// the input refs plus their children, so we don't have to redo later the recursing
		// work that we're alreading doing in checkFiles.
		dh.pathByRef = make(map[blob.Ref]string, len(refs))
		err := dh.checkFiles(ctx, "", refs)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		allRefs = dh.pathByRef
	} else {
		_, ok := dh.Fetcher.(blobserver.BlobStatter)
		if ok {
			if err := dh.statFiles(refs); err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
		}
		// If we don't have a cacher we don't know yet of all the possible
		// children refs, so allRefs is just the input refs, and the
		// children will be discovered on the fly, while building the zip archive.
		// This is the case even if we have a statter, because statFiles does not
		// recurse into directories.
		allRefs = make(map[blob.Ref]string, len(refs))
		for _, v := range refs {
			allRefs[v] = ""
		}
	}

	h := w.Header()
	h.Set("Content-Type", "application/zip")
	zipName := "camli-download-" + time.Now().Format(downloadTimeLayout) + ".zip"
	h.Set("Content-Disposition", "attachment; filename="+zipName)
	zw := zip.NewWriter(w)
	dh.r = r
	for br := range allRefs {
		if err := dh.zipFile(ctx, "", br, zw); err != nil {
			log.Printf("error zipping %v: %v", br, err)
			// http.Error is of no use since we've already started sending a response
			panic(http.ErrAbortHandler)
		}
	}
	if err := zw.Close(); err != nil {
		log.Printf("error closing zip stream: %v", err)
		panic(http.ErrAbortHandler)
	}
}
857963
func genArchive() ([]string, error) {
	switch *flagArchiveType {
	case "linux", "darwin", "windows":
		genBinaries(*flagArchiveType)
		return []string{packBinaries(*flagArchiveType)}, nil
	case "src":
		return []string{zipSource()}, nil
	default:
		return genAll()
	}
}
756437
func (*Zip) CheckExt(filename string) error {
	if !strings.HasSuffix(filename, ".zip") {
		return fmt.Errorf("filename must have a .zip extension")
	}
	return nil
}
1239536
func (d Data) FileExists(key string) bool {
	_, found := d.Files[key]
	return found
}
447715
func Zipit(source, target, prefix string) error {
	// Thanks to Svett Ralchev
	// http://blog.ralch.com/tutorial/golang-working-with-zip/

	zipfile, err := os.Create(target)
	if err != nil {
		return err
	}
	defer zipfile.Close()

	if prefix != "" {
		_, err = io.WriteString(zipfile, prefix)
		if err != nil {
			return err
		}
	}

	archive := zip.NewWriter(zipfile)
	defer archive.Close()

	err = filepath.Walk(source, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}

		if path == source {
			return nil
		}

		header, err := zip.FileInfoHeader(info)
		if err != nil {
			return err
		}
		header.Name, err = filepath.Rel(source, path)
		if err != nil {
			return err
		}

		header.Name = filepath.ToSlash(header.Name)

		if info.IsDir() {
			header.Name += "/"
			header.SetMode(0755)
		} else {
			header.Method = zip.Deflate
			header.SetMode(0744)
		}

		writer, err := archive.CreateHeader(header)
		if err != nil {
			return err
		}

		if info.IsDir() {
			return nil
		}

		file, err := os.Open(path)
		if err != nil {
			return err
		}
		defer file.Close()

		_, err = io.Copy(writer, file)
		return err
	})

	return err
}
1179392
func findExe(cmd string, paths []string) (string, bool) {
	for _, p := range paths {
		cp := filepath.Join(p, cmd)
		if c, err := exec.LookPath(cp); err == nil {
			return c, true
		}
	}
	return cmd, false
}
1044415
func (actor Actor) ZipDirectoryResources(sourceDir string, filesToInclude []Resource) (string, error) {
	log.WithField("sourceDir", sourceDir).Info("zipping source files from directory")
	zipFile, err := ioutil.TempFile("", "cf-cli-")
	if err != nil {
		return "", err
	}
	defer zipFile.Close()
	zipPath := zipFile.Name()

	writer := zip.NewWriter(zipFile)
	defer writer.Close()

	for _, resource := range filesToInclude {
		fullPath := filepath.Join(sourceDir, resource.Filename)
		log.WithField("fullPath", fullPath).Debug("zipping file")

		fileInfo, err := os.Lstat(fullPath)
		if err != nil {
			log.WithField("fullPath", fullPath).Errorln("stat error in dir:", err)
			return zipPath, err
		}

		log.WithField("file-mode", fileInfo.Mode().String()).Debug("resource file info")
		if fileInfo.Mode()&os.ModeSymlink == os.ModeSymlink {
			// we need to user os.Readlink to read a symlink file from a directory
			err = actor.addLinkToZipFromFileSystem(fullPath, fileInfo, resource, writer)
			if err != nil {
				log.WithField("fullPath", fullPath).Errorln("zipping file:", err)
				return zipPath, err
			}
		} else {
			srcFile, err := os.Open(fullPath)
			if err != nil {
				log.WithField("fullPath", fullPath).Errorln("opening path in dir:", err)
				return zipPath, err
			}
			defer srcFile.Close()

			err = actor.addFileToZipFromFileSystem(
				fullPath, srcFile, fileInfo,
				resource, writer,
			)
			srcFile.Close()
			if err != nil {
				log.WithField("fullPath", fullPath).Errorln("zipping file:", err)
				return zipPath, err
			}
		}
	}

	log.WithFields(log.Fields{
		"zip_file_location": zipFile.Name(),
		"zipped_file_count": len(filesToInclude),
	}).Info("zip file created")
	return zipPath, nil
}
831041
func (z *Zip) AddDir(root, target string) error {
	return filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}

		if !info.Mode().IsRegular() {
			return nil
		}

		file, err := os.Open(path)
		if err != nil {
			return err
		}
		defer file.Close()

		rel, err := filepath.Rel(root, path)
		if err != nil {
			return err
		}

		archivePath := filepath.Join(target, rel)
		return z.AddFile(archivePath, file)
	})
}
896607
func Zip(ctx context.Context, src, dst, dstRoot string) (err error) {
	// Create destination file
	var dstFile *os.File
	if dstFile, err = os.Create(dst); err != nil {
		return err
	}
	defer dstFile.Close()

	// Create zip writer
	var zw = zip.NewWriter(dstFile)
	defer zw.Close()

	// Walk
	filepath.Walk(src, func(path string, info os.FileInfo, e1 error) (e2 error) {
		// Process error
		if e1 != nil {
			return e1
		}

		// Init header
		var h *zip.FileHeader
		if h, e2 = zip.FileInfoHeader(info); e2 != nil {
			return
		}

		// Set header info
		h.Name = filepath.Join(dstRoot, strings.TrimPrefix(path, src))
		if info.IsDir() {
			h.Name += "/"
		} else {
			h.Method = zip.Deflate
		}

		// Create writer
		var w io.Writer
		if w, e2 = zw.CreateHeader(h); e2 != nil {
			return
		}

		// If path is dir, stop here
		if info.IsDir() {
			return
		}

		// Open path
		var walkFile *os.File
		if walkFile, e2 = os.Open(path); e2 != nil {
			return
		}
		defer walkFile.Close()

		// Copy
		if _, e2 = astiio.Copy(ctx, walkFile, w); e2 != nil {
			return
		}
		return
	})
	return
}
776428
func gzipAccepted(header http.Header) bool {
	a := header.Get(acceptEncodingHeader)
	parts := strings.Split(a, ",")
	for _, part := range parts {
		part = strings.TrimSpace(part)
		if part == "gzip" || strings.HasPrefix(part, "gzip;") {
			return true
		}
	}
	return false
}
700343
func ExtractZip(zipfile, destDir string) error {
	r, err := zip.OpenReader(zipfile)
	if err != nil {
		return err
	}
	defer r.Close()

	for _, f := range r.File {
		path := filepath.Join(destDir, filepath.Clean(f.Name))

		rc, err := f.Open()
		if err != nil {
			return err
		}

		if f.FileInfo().IsDir() {
			err = os.MkdirAll(path, f.Mode())
		} else {
			err = writeToFile(rc, path, f.Mode())
		}

		rc.Close()
		if err != nil {
			return err
		}
	}

	return nil
}
685020
func extractArchive(i interface{}, src io.Reader, dst string, opts *archive.TarOptions) error {
	if ea, ok := i.(extractor); ok {
		return ea.ExtractArchive(src, dst, opts)
	}
	return chrootarchive.Untar(src, dst, opts)
}
596764
func Unzip(archive string, target string) (string, error) {
	reader, err := zip.OpenReader(archive)
	if err != nil {
		return "", err
	}

	if err := os.MkdirAll(target, 0755); err != nil {
		return "", errDirCreate.Format(target, err.Error())
	}
	createdFolder := ""
	for _, file := range reader.File {
		path := filepath.Join(target, file.Name)
		if file.FileInfo().IsDir() {
			os.MkdirAll(path, file.Mode())
			if createdFolder == "" {
				// this is the new directory that zip has
				createdFolder = path
			}
			continue
		}

		fileReader, err := file.Open()
		if err != nil {
			return "", errFileOpen.Format(err.Error())
		}
		defer fileReader.Close()

		targetFile, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, file.Mode())
		if err != nil {
			return "", errFileOpen.Format(err.Error())
		}
		defer targetFile.Close()

		if _, err := io.Copy(targetFile, fileReader); err != nil {
			return "", errFileCopy.Format(err.Error())
		}

	}

	reader.Close()
	return createdFolder, nil
}