1*333d2b36SAndroid Build Coastguard Worker// Copyright 2015 Google Inc. All rights reserved. 2*333d2b36SAndroid Build Coastguard Worker// 3*333d2b36SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License"); 4*333d2b36SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License. 5*333d2b36SAndroid Build Coastguard Worker// You may obtain a copy of the License at 6*333d2b36SAndroid Build Coastguard Worker// 7*333d2b36SAndroid Build Coastguard Worker// http://www.apache.org/licenses/LICENSE-2.0 8*333d2b36SAndroid Build Coastguard Worker// 9*333d2b36SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software 10*333d2b36SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS, 11*333d2b36SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*333d2b36SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and 13*333d2b36SAndroid Build Coastguard Worker// limitations under the License. 14*333d2b36SAndroid Build Coastguard Worker 15*333d2b36SAndroid Build Coastguard Workerpackage zip 16*333d2b36SAndroid Build Coastguard Worker 17*333d2b36SAndroid Build Coastguard Workerimport ( 18*333d2b36SAndroid Build Coastguard Worker "bytes" 19*333d2b36SAndroid Build Coastguard Worker "compress/flate" 20*333d2b36SAndroid Build Coastguard Worker "crypto/sha256" 21*333d2b36SAndroid Build Coastguard Worker "encoding/binary" 22*333d2b36SAndroid Build Coastguard Worker "errors" 23*333d2b36SAndroid Build Coastguard Worker "fmt" 24*333d2b36SAndroid Build Coastguard Worker "hash" 25*333d2b36SAndroid Build Coastguard Worker "hash/crc32" 26*333d2b36SAndroid Build Coastguard Worker "io" 27*333d2b36SAndroid Build Coastguard Worker "io/ioutil" 28*333d2b36SAndroid Build Coastguard Worker "os" 29*333d2b36SAndroid Build Coastguard Worker "path/filepath" 30*333d2b36SAndroid Build Coastguard Worker "sort" 31*333d2b36SAndroid Build Coastguard Worker "strings" 32*333d2b36SAndroid Build Coastguard Worker "sync" 33*333d2b36SAndroid Build Coastguard Worker "syscall" 34*333d2b36SAndroid Build Coastguard Worker "time" 35*333d2b36SAndroid Build Coastguard Worker 36*333d2b36SAndroid Build Coastguard Worker "android/soong/response" 37*333d2b36SAndroid Build Coastguard Worker 38*333d2b36SAndroid Build Coastguard Worker "github.com/google/blueprint/pathtools" 39*333d2b36SAndroid Build Coastguard Worker 40*333d2b36SAndroid Build Coastguard Worker "android/soong/jar" 41*333d2b36SAndroid Build Coastguard Worker "android/soong/third_party/zip" 42*333d2b36SAndroid Build Coastguard Worker) 43*333d2b36SAndroid Build Coastguard Worker 44*333d2b36SAndroid Build Coastguard Worker// Sha256HeaderID is a custom Header ID for the `extra` field in 45*333d2b36SAndroid Build Coastguard Worker// the file header to store the SHA checksum. 46*333d2b36SAndroid Build Coastguard Workerconst Sha256HeaderID = 0x4967 47*333d2b36SAndroid Build Coastguard Worker 48*333d2b36SAndroid Build Coastguard Worker// Sha256HeaderSignature is the signature to verify that the extra 49*333d2b36SAndroid Build Coastguard Worker// data block is used to store the SHA checksum. 50*333d2b36SAndroid Build Coastguard Workerconst Sha256HeaderSignature = 0x9514 51*333d2b36SAndroid Build Coastguard Worker 52*333d2b36SAndroid Build Coastguard Worker// Block size used during parallel compression of a single file. 53*333d2b36SAndroid Build Coastguard Workerconst parallelBlockSize = 1 * 1024 * 1024 // 1MB 54*333d2b36SAndroid Build Coastguard Worker 55*333d2b36SAndroid Build Coastguard Worker// Minimum file size to use parallel compression. It requires more 56*333d2b36SAndroid Build Coastguard Worker// flate.Writer allocations, since we can't change the dictionary 57*333d2b36SAndroid Build Coastguard Worker// during Reset 58*333d2b36SAndroid Build Coastguard Workerconst minParallelFileSize = parallelBlockSize * 6 59*333d2b36SAndroid Build Coastguard Worker 60*333d2b36SAndroid Build Coastguard Worker// Size of the ZIP compression window (32KB) 61*333d2b36SAndroid Build Coastguard Workerconst windowSize = 32 * 1024 62*333d2b36SAndroid Build Coastguard Worker 63*333d2b36SAndroid Build Coastguard Workertype nopCloser struct { 64*333d2b36SAndroid Build Coastguard Worker io.Writer 65*333d2b36SAndroid Build Coastguard Worker} 66*333d2b36SAndroid Build Coastguard Worker 67*333d2b36SAndroid Build Coastguard Workerfunc (nopCloser) Close() error { 68*333d2b36SAndroid Build Coastguard Worker return nil 69*333d2b36SAndroid Build Coastguard Worker} 70*333d2b36SAndroid Build Coastguard Worker 71*333d2b36SAndroid Build Coastguard Workertype byteReaderCloser struct { 72*333d2b36SAndroid Build Coastguard Worker *bytes.Reader 73*333d2b36SAndroid Build Coastguard Worker io.Closer 74*333d2b36SAndroid Build Coastguard Worker} 75*333d2b36SAndroid Build Coastguard Worker 76*333d2b36SAndroid Build Coastguard Workertype pathMapping struct { 77*333d2b36SAndroid Build Coastguard Worker dest, src string 78*333d2b36SAndroid Build Coastguard Worker zipMethod uint16 79*333d2b36SAndroid Build Coastguard Worker} 80*333d2b36SAndroid Build Coastguard Worker 81*333d2b36SAndroid Build Coastguard Workertype FileArg struct { 82*333d2b36SAndroid Build Coastguard Worker PathPrefixInZip, SourcePrefixToStrip string 83*333d2b36SAndroid Build Coastguard Worker ExplicitPathInZip string 84*333d2b36SAndroid Build Coastguard Worker SourceFiles []string 85*333d2b36SAndroid Build Coastguard Worker JunkPaths bool 86*333d2b36SAndroid Build Coastguard Worker GlobDir string 87*333d2b36SAndroid Build Coastguard Worker} 88*333d2b36SAndroid Build Coastguard Worker 89*333d2b36SAndroid Build Coastguard Workertype FileArgsBuilder struct { 90*333d2b36SAndroid Build Coastguard Worker state FileArg 91*333d2b36SAndroid Build Coastguard Worker err error 92*333d2b36SAndroid Build Coastguard Worker fs pathtools.FileSystem 93*333d2b36SAndroid Build Coastguard Worker 94*333d2b36SAndroid Build Coastguard Worker fileArgs []FileArg 95*333d2b36SAndroid Build Coastguard Worker} 96*333d2b36SAndroid Build Coastguard Worker 97*333d2b36SAndroid Build Coastguard Workerfunc NewFileArgsBuilder() *FileArgsBuilder { 98*333d2b36SAndroid Build Coastguard Worker return &FileArgsBuilder{ 99*333d2b36SAndroid Build Coastguard Worker fs: pathtools.OsFs, 100*333d2b36SAndroid Build Coastguard Worker } 101*333d2b36SAndroid Build Coastguard Worker} 102*333d2b36SAndroid Build Coastguard Worker 103*333d2b36SAndroid Build Coastguard Workerfunc (b *FileArgsBuilder) JunkPaths(v bool) *FileArgsBuilder { 104*333d2b36SAndroid Build Coastguard Worker b.state.JunkPaths = v 105*333d2b36SAndroid Build Coastguard Worker b.state.SourcePrefixToStrip = "" 106*333d2b36SAndroid Build Coastguard Worker return b 107*333d2b36SAndroid Build Coastguard Worker} 108*333d2b36SAndroid Build Coastguard Worker 109*333d2b36SAndroid Build Coastguard Workerfunc (b *FileArgsBuilder) SourcePrefixToStrip(prefixToStrip string) *FileArgsBuilder { 110*333d2b36SAndroid Build Coastguard Worker b.state.JunkPaths = false 111*333d2b36SAndroid Build Coastguard Worker b.state.SourcePrefixToStrip = prefixToStrip 112*333d2b36SAndroid Build Coastguard Worker return b 113*333d2b36SAndroid Build Coastguard Worker} 114*333d2b36SAndroid Build Coastguard Worker 115*333d2b36SAndroid Build Coastguard Workerfunc (b *FileArgsBuilder) PathPrefixInZip(rootPrefix string) *FileArgsBuilder { 116*333d2b36SAndroid Build Coastguard Worker b.state.PathPrefixInZip = rootPrefix 117*333d2b36SAndroid Build Coastguard Worker return b 118*333d2b36SAndroid Build Coastguard Worker} 119*333d2b36SAndroid Build Coastguard Worker 120*333d2b36SAndroid Build Coastguard Workerfunc (b *FileArgsBuilder) File(name string) *FileArgsBuilder { 121*333d2b36SAndroid Build Coastguard Worker if b.err != nil { 122*333d2b36SAndroid Build Coastguard Worker return b 123*333d2b36SAndroid Build Coastguard Worker } 124*333d2b36SAndroid Build Coastguard Worker 125*333d2b36SAndroid Build Coastguard Worker arg := b.state 126*333d2b36SAndroid Build Coastguard Worker arg.SourceFiles = []string{name} 127*333d2b36SAndroid Build Coastguard Worker b.fileArgs = append(b.fileArgs, arg) 128*333d2b36SAndroid Build Coastguard Worker 129*333d2b36SAndroid Build Coastguard Worker if b.state.ExplicitPathInZip != "" { 130*333d2b36SAndroid Build Coastguard Worker b.state.ExplicitPathInZip = "" 131*333d2b36SAndroid Build Coastguard Worker } 132*333d2b36SAndroid Build Coastguard Worker return b 133*333d2b36SAndroid Build Coastguard Worker} 134*333d2b36SAndroid Build Coastguard Worker 135*333d2b36SAndroid Build Coastguard Workerfunc (b *FileArgsBuilder) Dir(name string) *FileArgsBuilder { 136*333d2b36SAndroid Build Coastguard Worker if b.err != nil { 137*333d2b36SAndroid Build Coastguard Worker return b 138*333d2b36SAndroid Build Coastguard Worker } 139*333d2b36SAndroid Build Coastguard Worker 140*333d2b36SAndroid Build Coastguard Worker arg := b.state 141*333d2b36SAndroid Build Coastguard Worker arg.GlobDir = name 142*333d2b36SAndroid Build Coastguard Worker b.fileArgs = append(b.fileArgs, arg) 143*333d2b36SAndroid Build Coastguard Worker return b 144*333d2b36SAndroid Build Coastguard Worker} 145*333d2b36SAndroid Build Coastguard Worker 146*333d2b36SAndroid Build Coastguard Worker// List reads the file names from the given file and adds them to the source files list. 147*333d2b36SAndroid Build Coastguard Workerfunc (b *FileArgsBuilder) List(name string) *FileArgsBuilder { 148*333d2b36SAndroid Build Coastguard Worker if b.err != nil { 149*333d2b36SAndroid Build Coastguard Worker return b 150*333d2b36SAndroid Build Coastguard Worker } 151*333d2b36SAndroid Build Coastguard Worker 152*333d2b36SAndroid Build Coastguard Worker f, err := b.fs.Open(name) 153*333d2b36SAndroid Build Coastguard Worker if err != nil { 154*333d2b36SAndroid Build Coastguard Worker b.err = err 155*333d2b36SAndroid Build Coastguard Worker return b 156*333d2b36SAndroid Build Coastguard Worker } 157*333d2b36SAndroid Build Coastguard Worker defer f.Close() 158*333d2b36SAndroid Build Coastguard Worker 159*333d2b36SAndroid Build Coastguard Worker list, err := ioutil.ReadAll(f) 160*333d2b36SAndroid Build Coastguard Worker if err != nil { 161*333d2b36SAndroid Build Coastguard Worker b.err = err 162*333d2b36SAndroid Build Coastguard Worker return b 163*333d2b36SAndroid Build Coastguard Worker } 164*333d2b36SAndroid Build Coastguard Worker 165*333d2b36SAndroid Build Coastguard Worker arg := b.state 166*333d2b36SAndroid Build Coastguard Worker arg.SourceFiles = strings.Fields(string(list)) 167*333d2b36SAndroid Build Coastguard Worker b.fileArgs = append(b.fileArgs, arg) 168*333d2b36SAndroid Build Coastguard Worker return b 169*333d2b36SAndroid Build Coastguard Worker} 170*333d2b36SAndroid Build Coastguard Worker 171*333d2b36SAndroid Build Coastguard Worker// RspFile reads the file names from given .rsp file and adds them to the source files list. 172*333d2b36SAndroid Build Coastguard Workerfunc (b *FileArgsBuilder) RspFile(name string) *FileArgsBuilder { 173*333d2b36SAndroid Build Coastguard Worker if b.err != nil { 174*333d2b36SAndroid Build Coastguard Worker return b 175*333d2b36SAndroid Build Coastguard Worker } 176*333d2b36SAndroid Build Coastguard Worker 177*333d2b36SAndroid Build Coastguard Worker f, err := b.fs.Open(name) 178*333d2b36SAndroid Build Coastguard Worker if err != nil { 179*333d2b36SAndroid Build Coastguard Worker b.err = err 180*333d2b36SAndroid Build Coastguard Worker return b 181*333d2b36SAndroid Build Coastguard Worker } 182*333d2b36SAndroid Build Coastguard Worker defer f.Close() 183*333d2b36SAndroid Build Coastguard Worker 184*333d2b36SAndroid Build Coastguard Worker arg := b.state 185*333d2b36SAndroid Build Coastguard Worker arg.SourceFiles, err = response.ReadRspFile(f) 186*333d2b36SAndroid Build Coastguard Worker if err != nil { 187*333d2b36SAndroid Build Coastguard Worker b.err = err 188*333d2b36SAndroid Build Coastguard Worker return b 189*333d2b36SAndroid Build Coastguard Worker } 190*333d2b36SAndroid Build Coastguard Worker for i := range arg.SourceFiles { 191*333d2b36SAndroid Build Coastguard Worker arg.SourceFiles[i] = pathtools.MatchEscape(arg.SourceFiles[i]) 192*333d2b36SAndroid Build Coastguard Worker } 193*333d2b36SAndroid Build Coastguard Worker b.fileArgs = append(b.fileArgs, arg) 194*333d2b36SAndroid Build Coastguard Worker return b 195*333d2b36SAndroid Build Coastguard Worker} 196*333d2b36SAndroid Build Coastguard Worker 197*333d2b36SAndroid Build Coastguard Worker// ExplicitPathInZip sets the path in the zip file for the next File call. 198*333d2b36SAndroid Build Coastguard Workerfunc (b *FileArgsBuilder) ExplicitPathInZip(s string) *FileArgsBuilder { 199*333d2b36SAndroid Build Coastguard Worker b.state.ExplicitPathInZip = s 200*333d2b36SAndroid Build Coastguard Worker return b 201*333d2b36SAndroid Build Coastguard Worker} 202*333d2b36SAndroid Build Coastguard Worker 203*333d2b36SAndroid Build Coastguard Workerfunc (b *FileArgsBuilder) Error() error { 204*333d2b36SAndroid Build Coastguard Worker if b == nil { 205*333d2b36SAndroid Build Coastguard Worker return nil 206*333d2b36SAndroid Build Coastguard Worker } 207*333d2b36SAndroid Build Coastguard Worker return b.err 208*333d2b36SAndroid Build Coastguard Worker} 209*333d2b36SAndroid Build Coastguard Worker 210*333d2b36SAndroid Build Coastguard Workerfunc (b *FileArgsBuilder) FileArgs() []FileArg { 211*333d2b36SAndroid Build Coastguard Worker if b == nil { 212*333d2b36SAndroid Build Coastguard Worker return nil 213*333d2b36SAndroid Build Coastguard Worker } 214*333d2b36SAndroid Build Coastguard Worker return b.fileArgs 215*333d2b36SAndroid Build Coastguard Worker} 216*333d2b36SAndroid Build Coastguard Worker 217*333d2b36SAndroid Build Coastguard Workertype IncorrectRelativeRootError struct { 218*333d2b36SAndroid Build Coastguard Worker RelativeRoot string 219*333d2b36SAndroid Build Coastguard Worker Path string 220*333d2b36SAndroid Build Coastguard Worker} 221*333d2b36SAndroid Build Coastguard Worker 222*333d2b36SAndroid Build Coastguard Workerfunc (x IncorrectRelativeRootError) Error() string { 223*333d2b36SAndroid Build Coastguard Worker return fmt.Sprintf("path %q is outside relative root %q", x.Path, x.RelativeRoot) 224*333d2b36SAndroid Build Coastguard Worker} 225*333d2b36SAndroid Build Coastguard Worker 226*333d2b36SAndroid Build Coastguard Workertype ConflictingFileError struct { 227*333d2b36SAndroid Build Coastguard Worker Dest string 228*333d2b36SAndroid Build Coastguard Worker Prev string 229*333d2b36SAndroid Build Coastguard Worker Src string 230*333d2b36SAndroid Build Coastguard Worker} 231*333d2b36SAndroid Build Coastguard Worker 232*333d2b36SAndroid Build Coastguard Workerfunc (x ConflictingFileError) Error() string { 233*333d2b36SAndroid Build Coastguard Worker return fmt.Sprintf("destination %q has two files %q and %q", x.Dest, x.Prev, x.Src) 234*333d2b36SAndroid Build Coastguard Worker} 235*333d2b36SAndroid Build Coastguard Worker 236*333d2b36SAndroid Build Coastguard Workertype ZipWriter struct { 237*333d2b36SAndroid Build Coastguard Worker time time.Time 238*333d2b36SAndroid Build Coastguard Worker createdFiles map[string]string 239*333d2b36SAndroid Build Coastguard Worker createdDirs map[string]string 240*333d2b36SAndroid Build Coastguard Worker directories bool 241*333d2b36SAndroid Build Coastguard Worker 242*333d2b36SAndroid Build Coastguard Worker errors chan error 243*333d2b36SAndroid Build Coastguard Worker writeOps chan chan *zipEntry 244*333d2b36SAndroid Build Coastguard Worker 245*333d2b36SAndroid Build Coastguard Worker cpuRateLimiter *CPURateLimiter 246*333d2b36SAndroid Build Coastguard Worker memoryRateLimiter *MemoryRateLimiter 247*333d2b36SAndroid Build Coastguard Worker 248*333d2b36SAndroid Build Coastguard Worker compressorPool sync.Pool 249*333d2b36SAndroid Build Coastguard Worker compLevel int 250*333d2b36SAndroid Build Coastguard Worker 251*333d2b36SAndroid Build Coastguard Worker followSymlinks pathtools.ShouldFollowSymlinks 252*333d2b36SAndroid Build Coastguard Worker ignoreMissingFiles bool 253*333d2b36SAndroid Build Coastguard Worker 254*333d2b36SAndroid Build Coastguard Worker stderr io.Writer 255*333d2b36SAndroid Build Coastguard Worker fs pathtools.FileSystem 256*333d2b36SAndroid Build Coastguard Worker 257*333d2b36SAndroid Build Coastguard Worker sha256Checksum bool 258*333d2b36SAndroid Build Coastguard Worker} 259*333d2b36SAndroid Build Coastguard Worker 260*333d2b36SAndroid Build Coastguard Workertype zipEntry struct { 261*333d2b36SAndroid Build Coastguard Worker fh *zip.FileHeader 262*333d2b36SAndroid Build Coastguard Worker 263*333d2b36SAndroid Build Coastguard Worker // List of delayed io.Reader 264*333d2b36SAndroid Build Coastguard Worker futureReaders chan chan io.Reader 265*333d2b36SAndroid Build Coastguard Worker 266*333d2b36SAndroid Build Coastguard Worker // Only used for passing into the MemoryRateLimiter to ensure we 267*333d2b36SAndroid Build Coastguard Worker // release as much memory as much as we request 268*333d2b36SAndroid Build Coastguard Worker allocatedSize int64 269*333d2b36SAndroid Build Coastguard Worker} 270*333d2b36SAndroid Build Coastguard Worker 271*333d2b36SAndroid Build Coastguard Workertype ZipArgs struct { 272*333d2b36SAndroid Build Coastguard Worker FileArgs []FileArg 273*333d2b36SAndroid Build Coastguard Worker OutputFilePath string 274*333d2b36SAndroid Build Coastguard Worker EmulateJar bool 275*333d2b36SAndroid Build Coastguard Worker SrcJar bool 276*333d2b36SAndroid Build Coastguard Worker AddDirectoryEntriesToZip bool 277*333d2b36SAndroid Build Coastguard Worker CompressionLevel int 278*333d2b36SAndroid Build Coastguard Worker ManifestSourcePath string 279*333d2b36SAndroid Build Coastguard Worker NumParallelJobs int 280*333d2b36SAndroid Build Coastguard Worker NonDeflatedFiles map[string]bool 281*333d2b36SAndroid Build Coastguard Worker WriteIfChanged bool 282*333d2b36SAndroid Build Coastguard Worker StoreSymlinks bool 283*333d2b36SAndroid Build Coastguard Worker IgnoreMissingFiles bool 284*333d2b36SAndroid Build Coastguard Worker Sha256Checksum bool 285*333d2b36SAndroid Build Coastguard Worker DoNotWrite bool 286*333d2b36SAndroid Build Coastguard Worker Quiet bool 287*333d2b36SAndroid Build Coastguard Worker 288*333d2b36SAndroid Build Coastguard Worker Stderr io.Writer 289*333d2b36SAndroid Build Coastguard Worker Filesystem pathtools.FileSystem 290*333d2b36SAndroid Build Coastguard Worker} 291*333d2b36SAndroid Build Coastguard Worker 292*333d2b36SAndroid Build Coastguard Workerfunc zipTo(args ZipArgs, w io.Writer) error { 293*333d2b36SAndroid Build Coastguard Worker if args.EmulateJar { 294*333d2b36SAndroid Build Coastguard Worker args.AddDirectoryEntriesToZip = true 295*333d2b36SAndroid Build Coastguard Worker } 296*333d2b36SAndroid Build Coastguard Worker 297*333d2b36SAndroid Build Coastguard Worker // Have Glob follow symlinks if they are not being stored as symlinks in the zip file. 298*333d2b36SAndroid Build Coastguard Worker followSymlinks := pathtools.ShouldFollowSymlinks(!args.StoreSymlinks) 299*333d2b36SAndroid Build Coastguard Worker 300*333d2b36SAndroid Build Coastguard Worker z := &ZipWriter{ 301*333d2b36SAndroid Build Coastguard Worker time: jar.DefaultTime, 302*333d2b36SAndroid Build Coastguard Worker createdDirs: make(map[string]string), 303*333d2b36SAndroid Build Coastguard Worker createdFiles: make(map[string]string), 304*333d2b36SAndroid Build Coastguard Worker directories: args.AddDirectoryEntriesToZip, 305*333d2b36SAndroid Build Coastguard Worker compLevel: args.CompressionLevel, 306*333d2b36SAndroid Build Coastguard Worker followSymlinks: followSymlinks, 307*333d2b36SAndroid Build Coastguard Worker ignoreMissingFiles: args.IgnoreMissingFiles, 308*333d2b36SAndroid Build Coastguard Worker stderr: args.Stderr, 309*333d2b36SAndroid Build Coastguard Worker fs: args.Filesystem, 310*333d2b36SAndroid Build Coastguard Worker sha256Checksum: args.Sha256Checksum, 311*333d2b36SAndroid Build Coastguard Worker } 312*333d2b36SAndroid Build Coastguard Worker 313*333d2b36SAndroid Build Coastguard Worker if z.fs == nil { 314*333d2b36SAndroid Build Coastguard Worker z.fs = pathtools.OsFs 315*333d2b36SAndroid Build Coastguard Worker } 316*333d2b36SAndroid Build Coastguard Worker 317*333d2b36SAndroid Build Coastguard Worker if z.stderr == nil { 318*333d2b36SAndroid Build Coastguard Worker z.stderr = os.Stderr 319*333d2b36SAndroid Build Coastguard Worker } 320*333d2b36SAndroid Build Coastguard Worker 321*333d2b36SAndroid Build Coastguard Worker pathMappings := []pathMapping{} 322*333d2b36SAndroid Build Coastguard Worker 323*333d2b36SAndroid Build Coastguard Worker noCompression := args.CompressionLevel == 0 324*333d2b36SAndroid Build Coastguard Worker 325*333d2b36SAndroid Build Coastguard Worker for _, fa := range args.FileArgs { 326*333d2b36SAndroid Build Coastguard Worker var srcs []string 327*333d2b36SAndroid Build Coastguard Worker for _, s := range fa.SourceFiles { 328*333d2b36SAndroid Build Coastguard Worker s = strings.TrimSpace(s) 329*333d2b36SAndroid Build Coastguard Worker if s == "" { 330*333d2b36SAndroid Build Coastguard Worker continue 331*333d2b36SAndroid Build Coastguard Worker } 332*333d2b36SAndroid Build Coastguard Worker 333*333d2b36SAndroid Build Coastguard Worker result, err := z.fs.Glob(s, nil, followSymlinks) 334*333d2b36SAndroid Build Coastguard Worker if err != nil { 335*333d2b36SAndroid Build Coastguard Worker return err 336*333d2b36SAndroid Build Coastguard Worker } 337*333d2b36SAndroid Build Coastguard Worker if len(result.Matches) == 0 { 338*333d2b36SAndroid Build Coastguard Worker err := &os.PathError{ 339*333d2b36SAndroid Build Coastguard Worker Op: "lstat", 340*333d2b36SAndroid Build Coastguard Worker Path: s, 341*333d2b36SAndroid Build Coastguard Worker Err: os.ErrNotExist, 342*333d2b36SAndroid Build Coastguard Worker } 343*333d2b36SAndroid Build Coastguard Worker if args.IgnoreMissingFiles { 344*333d2b36SAndroid Build Coastguard Worker if !args.Quiet { 345*333d2b36SAndroid Build Coastguard Worker fmt.Fprintln(z.stderr, "warning:", err) 346*333d2b36SAndroid Build Coastguard Worker } 347*333d2b36SAndroid Build Coastguard Worker } else { 348*333d2b36SAndroid Build Coastguard Worker return err 349*333d2b36SAndroid Build Coastguard Worker } 350*333d2b36SAndroid Build Coastguard Worker } 351*333d2b36SAndroid Build Coastguard Worker srcs = append(srcs, result.Matches...) 352*333d2b36SAndroid Build Coastguard Worker } 353*333d2b36SAndroid Build Coastguard Worker if fa.GlobDir != "" { 354*333d2b36SAndroid Build Coastguard Worker if exists, isDir, err := z.fs.Exists(fa.GlobDir); err != nil { 355*333d2b36SAndroid Build Coastguard Worker return err 356*333d2b36SAndroid Build Coastguard Worker } else if !exists && !args.IgnoreMissingFiles { 357*333d2b36SAndroid Build Coastguard Worker err := &os.PathError{ 358*333d2b36SAndroid Build Coastguard Worker Op: "lstat", 359*333d2b36SAndroid Build Coastguard Worker Path: fa.GlobDir, 360*333d2b36SAndroid Build Coastguard Worker Err: os.ErrNotExist, 361*333d2b36SAndroid Build Coastguard Worker } 362*333d2b36SAndroid Build Coastguard Worker if args.IgnoreMissingFiles { 363*333d2b36SAndroid Build Coastguard Worker if !args.Quiet { 364*333d2b36SAndroid Build Coastguard Worker fmt.Fprintln(z.stderr, "warning:", err) 365*333d2b36SAndroid Build Coastguard Worker } 366*333d2b36SAndroid Build Coastguard Worker } else { 367*333d2b36SAndroid Build Coastguard Worker return err 368*333d2b36SAndroid Build Coastguard Worker } 369*333d2b36SAndroid Build Coastguard Worker } else if !isDir && !args.IgnoreMissingFiles { 370*333d2b36SAndroid Build Coastguard Worker err := &os.PathError{ 371*333d2b36SAndroid Build Coastguard Worker Op: "lstat", 372*333d2b36SAndroid Build Coastguard Worker Path: fa.GlobDir, 373*333d2b36SAndroid Build Coastguard Worker Err: syscall.ENOTDIR, 374*333d2b36SAndroid Build Coastguard Worker } 375*333d2b36SAndroid Build Coastguard Worker if args.IgnoreMissingFiles { 376*333d2b36SAndroid Build Coastguard Worker if !args.Quiet { 377*333d2b36SAndroid Build Coastguard Worker fmt.Fprintln(z.stderr, "warning:", err) 378*333d2b36SAndroid Build Coastguard Worker } 379*333d2b36SAndroid Build Coastguard Worker } else { 380*333d2b36SAndroid Build Coastguard Worker return err 381*333d2b36SAndroid Build Coastguard Worker } 382*333d2b36SAndroid Build Coastguard Worker } 383*333d2b36SAndroid Build Coastguard Worker result, err := z.fs.Glob(filepath.Join(fa.GlobDir, "**/*"), nil, followSymlinks) 384*333d2b36SAndroid Build Coastguard Worker if err != nil { 385*333d2b36SAndroid Build Coastguard Worker return err 386*333d2b36SAndroid Build Coastguard Worker } 387*333d2b36SAndroid Build Coastguard Worker srcs = append(srcs, result.Matches...) 388*333d2b36SAndroid Build Coastguard Worker } 389*333d2b36SAndroid Build Coastguard Worker for _, src := range srcs { 390*333d2b36SAndroid Build Coastguard Worker err := fillPathPairs(fa, src, &pathMappings, args.NonDeflatedFiles, noCompression) 391*333d2b36SAndroid Build Coastguard Worker if err != nil { 392*333d2b36SAndroid Build Coastguard Worker return err 393*333d2b36SAndroid Build Coastguard Worker } 394*333d2b36SAndroid Build Coastguard Worker } 395*333d2b36SAndroid Build Coastguard Worker } 396*333d2b36SAndroid Build Coastguard Worker 397*333d2b36SAndroid Build Coastguard Worker return z.write(w, pathMappings, args.ManifestSourcePath, args.EmulateJar, args.SrcJar, args.NumParallelJobs) 398*333d2b36SAndroid Build Coastguard Worker} 399*333d2b36SAndroid Build Coastguard Worker 400*333d2b36SAndroid Build Coastguard Worker// Zip creates an output zip archive from given sources. 401*333d2b36SAndroid Build Coastguard Workerfunc Zip(args ZipArgs) error { 402*333d2b36SAndroid Build Coastguard Worker if args.OutputFilePath == "" { 403*333d2b36SAndroid Build Coastguard Worker return fmt.Errorf("output file path must be nonempty") 404*333d2b36SAndroid Build Coastguard Worker } 405*333d2b36SAndroid Build Coastguard Worker 406*333d2b36SAndroid Build Coastguard Worker buf := &bytes.Buffer{} 407*333d2b36SAndroid Build Coastguard Worker var out io.Writer = buf 408*333d2b36SAndroid Build Coastguard Worker 409*333d2b36SAndroid Build Coastguard Worker var zipErr error 410*333d2b36SAndroid Build Coastguard Worker 411*333d2b36SAndroid Build Coastguard Worker if args.DoNotWrite { 412*333d2b36SAndroid Build Coastguard Worker out = io.Discard 413*333d2b36SAndroid Build Coastguard Worker } else if !args.WriteIfChanged { 414*333d2b36SAndroid Build Coastguard Worker f, err := os.Create(args.OutputFilePath) 415*333d2b36SAndroid Build Coastguard Worker if err != nil { 416*333d2b36SAndroid Build Coastguard Worker return err 417*333d2b36SAndroid Build Coastguard Worker } 418*333d2b36SAndroid Build Coastguard Worker 419*333d2b36SAndroid Build Coastguard Worker defer f.Close() 420*333d2b36SAndroid Build Coastguard Worker defer func() { 421*333d2b36SAndroid Build Coastguard Worker if zipErr != nil { 422*333d2b36SAndroid Build Coastguard Worker os.Remove(args.OutputFilePath) 423*333d2b36SAndroid Build Coastguard Worker } 424*333d2b36SAndroid Build Coastguard Worker }() 425*333d2b36SAndroid Build Coastguard Worker 426*333d2b36SAndroid Build Coastguard Worker out = f 427*333d2b36SAndroid Build Coastguard Worker } 428*333d2b36SAndroid Build Coastguard Worker 429*333d2b36SAndroid Build Coastguard Worker zipErr = zipTo(args, out) 430*333d2b36SAndroid Build Coastguard Worker if zipErr != nil { 431*333d2b36SAndroid Build Coastguard Worker return zipErr 432*333d2b36SAndroid Build Coastguard Worker } 433*333d2b36SAndroid Build Coastguard Worker 434*333d2b36SAndroid Build Coastguard Worker if args.WriteIfChanged && !args.DoNotWrite { 435*333d2b36SAndroid Build Coastguard Worker err := pathtools.WriteFileIfChanged(args.OutputFilePath, buf.Bytes(), 0666) 436*333d2b36SAndroid Build Coastguard Worker if err != nil { 437*333d2b36SAndroid Build Coastguard Worker return err 438*333d2b36SAndroid Build Coastguard Worker } 439*333d2b36SAndroid Build Coastguard Worker } 440*333d2b36SAndroid Build Coastguard Worker 441*333d2b36SAndroid Build Coastguard Worker return nil 442*333d2b36SAndroid Build Coastguard Worker} 443*333d2b36SAndroid Build Coastguard Worker 444*333d2b36SAndroid Build Coastguard Workerfunc fillPathPairs(fa FileArg, src string, pathMappings *[]pathMapping, 445*333d2b36SAndroid Build Coastguard Worker nonDeflatedFiles map[string]bool, noCompression bool) error { 446*333d2b36SAndroid Build Coastguard Worker 447*333d2b36SAndroid Build Coastguard Worker var dest string 448*333d2b36SAndroid Build Coastguard Worker 449*333d2b36SAndroid Build Coastguard Worker if fa.ExplicitPathInZip != "" { 450*333d2b36SAndroid Build Coastguard Worker dest = fa.ExplicitPathInZip 451*333d2b36SAndroid Build Coastguard Worker } else if fa.JunkPaths { 452*333d2b36SAndroid Build Coastguard Worker dest = filepath.Base(src) 453*333d2b36SAndroid Build Coastguard Worker } else { 454*333d2b36SAndroid Build Coastguard Worker var err error 455*333d2b36SAndroid Build Coastguard Worker dest, err = filepath.Rel(fa.SourcePrefixToStrip, src) 456*333d2b36SAndroid Build Coastguard Worker if err != nil { 457*333d2b36SAndroid Build Coastguard Worker return err 458*333d2b36SAndroid Build Coastguard Worker } 459*333d2b36SAndroid Build Coastguard Worker if strings.HasPrefix(dest, "../") { 460*333d2b36SAndroid Build Coastguard Worker return IncorrectRelativeRootError{ 461*333d2b36SAndroid Build Coastguard Worker Path: src, 462*333d2b36SAndroid Build Coastguard Worker RelativeRoot: fa.SourcePrefixToStrip, 463*333d2b36SAndroid Build Coastguard Worker } 464*333d2b36SAndroid Build Coastguard Worker } 465*333d2b36SAndroid Build Coastguard Worker } 466*333d2b36SAndroid Build Coastguard Worker dest = filepath.Join(fa.PathPrefixInZip, dest) 467*333d2b36SAndroid Build Coastguard Worker 468*333d2b36SAndroid Build Coastguard Worker zipMethod := zip.Deflate 469*333d2b36SAndroid Build Coastguard Worker if _, found := nonDeflatedFiles[dest]; found || noCompression { 470*333d2b36SAndroid Build Coastguard Worker zipMethod = zip.Store 471*333d2b36SAndroid Build Coastguard Worker } 472*333d2b36SAndroid Build Coastguard Worker *pathMappings = append(*pathMappings, 473*333d2b36SAndroid Build Coastguard Worker pathMapping{dest: dest, src: src, zipMethod: zipMethod}) 474*333d2b36SAndroid Build Coastguard Worker 475*333d2b36SAndroid Build Coastguard Worker return nil 476*333d2b36SAndroid Build Coastguard Worker} 477*333d2b36SAndroid Build Coastguard Worker 478*333d2b36SAndroid Build Coastguard Workerfunc jarSort(mappings []pathMapping) { 479*333d2b36SAndroid Build Coastguard Worker sort.SliceStable(mappings, func(i int, j int) bool { 480*333d2b36SAndroid Build Coastguard Worker return jar.EntryNamesLess(mappings[i].dest, mappings[j].dest) 481*333d2b36SAndroid Build Coastguard Worker }) 482*333d2b36SAndroid Build Coastguard Worker} 483*333d2b36SAndroid Build Coastguard Worker 484*333d2b36SAndroid Build Coastguard Workerfunc (z *ZipWriter) write(f io.Writer, pathMappings []pathMapping, manifest string, emulateJar, srcJar bool, 485*333d2b36SAndroid Build Coastguard Worker parallelJobs int) error { 486*333d2b36SAndroid Build Coastguard Worker 487*333d2b36SAndroid Build Coastguard Worker z.errors = make(chan error) 488*333d2b36SAndroid Build Coastguard Worker defer close(z.errors) 489*333d2b36SAndroid Build Coastguard Worker 490*333d2b36SAndroid Build Coastguard Worker // This channel size can be essentially unlimited -- it's used as a fifo 491*333d2b36SAndroid Build Coastguard Worker // queue decouple the CPU and IO loads. Directories don't require any 492*333d2b36SAndroid Build Coastguard Worker // compression time, but still cost some IO. Similar with small files that 493*333d2b36SAndroid Build Coastguard Worker // can be very fast to compress. Some files that are more difficult to 494*333d2b36SAndroid Build Coastguard Worker // compress won't take a corresponding longer time writing out. 495*333d2b36SAndroid Build Coastguard Worker // 496*333d2b36SAndroid Build Coastguard Worker // The optimum size here depends on your CPU and IO characteristics, and 497*333d2b36SAndroid Build Coastguard Worker // the the layout of your zip file. 1000 was chosen mostly at random as 498*333d2b36SAndroid Build Coastguard Worker // something that worked reasonably well for a test file. 499*333d2b36SAndroid Build Coastguard Worker // 500*333d2b36SAndroid Build Coastguard Worker // The RateLimit object will put the upper bounds on the number of 501*333d2b36SAndroid Build Coastguard Worker // parallel compressions and outstanding buffers. 502*333d2b36SAndroid Build Coastguard Worker z.writeOps = make(chan chan *zipEntry, 1000) 503*333d2b36SAndroid Build Coastguard Worker z.cpuRateLimiter = NewCPURateLimiter(int64(parallelJobs)) 504*333d2b36SAndroid Build Coastguard Worker z.memoryRateLimiter = NewMemoryRateLimiter(0) 505*333d2b36SAndroid Build Coastguard Worker defer func() { 506*333d2b36SAndroid Build Coastguard Worker z.cpuRateLimiter.Stop() 507*333d2b36SAndroid Build Coastguard Worker z.memoryRateLimiter.Stop() 508*333d2b36SAndroid Build Coastguard Worker }() 509*333d2b36SAndroid Build Coastguard Worker 510*333d2b36SAndroid Build Coastguard Worker if manifest != "" && !emulateJar { 511*333d2b36SAndroid Build Coastguard Worker return errors.New("must specify --jar when specifying a manifest via -m") 512*333d2b36SAndroid Build Coastguard Worker } 513*333d2b36SAndroid Build Coastguard Worker 514*333d2b36SAndroid Build Coastguard Worker if emulateJar { 515*333d2b36SAndroid Build Coastguard Worker // manifest may be empty, in which case addManifest will fill in a default 516*333d2b36SAndroid Build Coastguard Worker pathMappings = append(pathMappings, pathMapping{jar.ManifestFile, manifest, zip.Deflate}) 517*333d2b36SAndroid Build Coastguard Worker 518*333d2b36SAndroid Build Coastguard Worker jarSort(pathMappings) 519*333d2b36SAndroid Build Coastguard Worker } 520*333d2b36SAndroid Build Coastguard Worker 521*333d2b36SAndroid Build Coastguard Worker go func() { 522*333d2b36SAndroid Build Coastguard Worker var err error 523*333d2b36SAndroid Build Coastguard Worker defer close(z.writeOps) 524*333d2b36SAndroid Build Coastguard Worker 525*333d2b36SAndroid Build Coastguard Worker for _, ele := range pathMappings { 526*333d2b36SAndroid Build Coastguard Worker if emulateJar && ele.dest == jar.ManifestFile { 527*333d2b36SAndroid Build Coastguard Worker err = z.addManifest(ele.dest, ele.src, ele.zipMethod) 528*333d2b36SAndroid Build Coastguard Worker } else { 529*333d2b36SAndroid Build Coastguard Worker err = z.addFile(ele.dest, ele.src, ele.zipMethod, emulateJar, srcJar) 530*333d2b36SAndroid Build Coastguard Worker } 531*333d2b36SAndroid Build Coastguard Worker if err != nil { 532*333d2b36SAndroid Build Coastguard Worker z.errors <- err 533*333d2b36SAndroid Build Coastguard Worker return 534*333d2b36SAndroid Build Coastguard Worker } 535*333d2b36SAndroid Build Coastguard Worker } 536*333d2b36SAndroid Build Coastguard Worker }() 537*333d2b36SAndroid Build Coastguard Worker 538*333d2b36SAndroid Build Coastguard Worker zipw := zip.NewWriter(f) 539*333d2b36SAndroid Build Coastguard Worker 540*333d2b36SAndroid Build Coastguard Worker var currentWriteOpChan chan *zipEntry 541*333d2b36SAndroid Build Coastguard Worker var currentWriter io.WriteCloser 542*333d2b36SAndroid Build Coastguard Worker var currentReaders chan chan io.Reader 543*333d2b36SAndroid Build Coastguard Worker var currentReader chan io.Reader 544*333d2b36SAndroid Build Coastguard Worker var done bool 545*333d2b36SAndroid Build Coastguard Worker 546*333d2b36SAndroid Build Coastguard Worker for !done { 547*333d2b36SAndroid Build Coastguard Worker var writeOpsChan chan chan *zipEntry 548*333d2b36SAndroid Build Coastguard Worker var writeOpChan chan *zipEntry 549*333d2b36SAndroid Build Coastguard Worker var readersChan chan chan io.Reader 550*333d2b36SAndroid Build Coastguard Worker 551*333d2b36SAndroid Build Coastguard Worker if currentReader != nil { 552*333d2b36SAndroid Build Coastguard Worker // Only read and process errors 553*333d2b36SAndroid Build Coastguard Worker } else if currentReaders != nil { 554*333d2b36SAndroid Build Coastguard Worker readersChan = currentReaders 555*333d2b36SAndroid Build Coastguard Worker } else if currentWriteOpChan != nil { 556*333d2b36SAndroid Build Coastguard Worker writeOpChan = currentWriteOpChan 557*333d2b36SAndroid Build Coastguard Worker } else { 558*333d2b36SAndroid Build Coastguard Worker writeOpsChan = z.writeOps 559*333d2b36SAndroid Build Coastguard Worker } 560*333d2b36SAndroid Build Coastguard Worker 561*333d2b36SAndroid Build Coastguard Worker select { 562*333d2b36SAndroid Build Coastguard Worker case writeOp, ok := <-writeOpsChan: 563*333d2b36SAndroid Build Coastguard Worker if !ok { 564*333d2b36SAndroid Build Coastguard Worker done = true 565*333d2b36SAndroid Build Coastguard Worker } 566*333d2b36SAndroid Build Coastguard Worker 567*333d2b36SAndroid Build Coastguard Worker currentWriteOpChan = writeOp 568*333d2b36SAndroid Build Coastguard Worker 569*333d2b36SAndroid Build Coastguard Worker case op := <-writeOpChan: 570*333d2b36SAndroid Build Coastguard Worker currentWriteOpChan = nil 571*333d2b36SAndroid Build Coastguard Worker 572*333d2b36SAndroid Build Coastguard Worker var err error 573*333d2b36SAndroid Build Coastguard Worker if op.fh.Method == zip.Deflate { 574*333d2b36SAndroid Build Coastguard Worker currentWriter, err = zipw.CreateCompressedHeader(op.fh) 575*333d2b36SAndroid Build Coastguard Worker } else { 576*333d2b36SAndroid Build Coastguard Worker var zw io.Writer 577*333d2b36SAndroid Build Coastguard Worker 578*333d2b36SAndroid Build Coastguard Worker op.fh.CompressedSize64 = op.fh.UncompressedSize64 579*333d2b36SAndroid Build Coastguard Worker 580*333d2b36SAndroid Build Coastguard Worker zw, err = zipw.CreateHeaderAndroid(op.fh) 581*333d2b36SAndroid Build Coastguard Worker currentWriter = nopCloser{zw} 582*333d2b36SAndroid Build Coastguard Worker } 583*333d2b36SAndroid Build Coastguard Worker if err != nil { 584*333d2b36SAndroid Build Coastguard Worker return err 585*333d2b36SAndroid Build Coastguard Worker } 586*333d2b36SAndroid Build Coastguard Worker 587*333d2b36SAndroid Build Coastguard Worker currentReaders = op.futureReaders 588*333d2b36SAndroid Build Coastguard Worker if op.futureReaders == nil { 589*333d2b36SAndroid Build Coastguard Worker currentWriter.Close() 590*333d2b36SAndroid Build Coastguard Worker currentWriter = nil 591*333d2b36SAndroid Build Coastguard Worker } 592*333d2b36SAndroid Build Coastguard Worker z.memoryRateLimiter.Finish(op.allocatedSize) 593*333d2b36SAndroid Build Coastguard Worker 594*333d2b36SAndroid Build Coastguard Worker case futureReader, ok := <-readersChan: 595*333d2b36SAndroid Build Coastguard Worker if !ok { 596*333d2b36SAndroid Build Coastguard Worker // Done with reading 597*333d2b36SAndroid Build Coastguard Worker currentWriter.Close() 598*333d2b36SAndroid Build Coastguard Worker currentWriter = nil 599*333d2b36SAndroid Build Coastguard Worker currentReaders = nil 600*333d2b36SAndroid Build Coastguard Worker } 601*333d2b36SAndroid Build Coastguard Worker 602*333d2b36SAndroid Build Coastguard Worker currentReader = futureReader 603*333d2b36SAndroid Build Coastguard Worker 604*333d2b36SAndroid Build Coastguard Worker case reader := <-currentReader: 605*333d2b36SAndroid Build Coastguard Worker _, err := io.Copy(currentWriter, reader) 606*333d2b36SAndroid Build Coastguard Worker if err != nil { 607*333d2b36SAndroid Build Coastguard Worker return err 608*333d2b36SAndroid Build Coastguard Worker } 609*333d2b36SAndroid Build Coastguard Worker 610*333d2b36SAndroid Build Coastguard Worker currentReader = nil 611*333d2b36SAndroid Build Coastguard Worker 612*333d2b36SAndroid Build Coastguard Worker case err := <-z.errors: 613*333d2b36SAndroid Build Coastguard Worker return err 614*333d2b36SAndroid Build Coastguard Worker } 615*333d2b36SAndroid Build Coastguard Worker } 616*333d2b36SAndroid Build Coastguard Worker 617*333d2b36SAndroid Build Coastguard Worker // One last chance to catch an error 618*333d2b36SAndroid Build Coastguard Worker select { 619*333d2b36SAndroid Build Coastguard Worker case err := <-z.errors: 620*333d2b36SAndroid Build Coastguard Worker return err 621*333d2b36SAndroid Build Coastguard Worker default: 622*333d2b36SAndroid Build Coastguard Worker zipw.Close() 623*333d2b36SAndroid Build Coastguard Worker return nil 624*333d2b36SAndroid Build Coastguard Worker } 625*333d2b36SAndroid Build Coastguard Worker} 626*333d2b36SAndroid Build Coastguard Worker 627*333d2b36SAndroid Build Coastguard Worker// imports (possibly with compression) <src> into the zip at sub-path <dest> 628*333d2b36SAndroid Build Coastguard Workerfunc (z *ZipWriter) addFile(dest, src string, method uint16, emulateJar, srcJar bool) error { 629*333d2b36SAndroid Build Coastguard Worker var fileSize int64 630*333d2b36SAndroid Build Coastguard Worker var executable bool 631*333d2b36SAndroid Build Coastguard Worker 632*333d2b36SAndroid Build Coastguard Worker var s os.FileInfo 633*333d2b36SAndroid Build Coastguard Worker var err error 634*333d2b36SAndroid Build Coastguard Worker if z.followSymlinks { 635*333d2b36SAndroid Build Coastguard Worker s, err = z.fs.Stat(src) 636*333d2b36SAndroid Build Coastguard Worker } else { 637*333d2b36SAndroid Build Coastguard Worker s, err = z.fs.Lstat(src) 638*333d2b36SAndroid Build Coastguard Worker } 639*333d2b36SAndroid Build Coastguard Worker 640*333d2b36SAndroid Build Coastguard Worker if err != nil { 641*333d2b36SAndroid Build Coastguard Worker if os.IsNotExist(err) && z.ignoreMissingFiles { 642*333d2b36SAndroid Build Coastguard Worker fmt.Fprintln(z.stderr, "warning:", err) 643*333d2b36SAndroid Build Coastguard Worker return nil 644*333d2b36SAndroid Build Coastguard Worker } 645*333d2b36SAndroid Build Coastguard Worker return err 646*333d2b36SAndroid Build Coastguard Worker } 647*333d2b36SAndroid Build Coastguard Worker 648*333d2b36SAndroid Build Coastguard Worker createParentDirs := func(dest, src string) error { 649*333d2b36SAndroid Build Coastguard Worker if err := z.writeDirectory(filepath.Dir(dest), src, emulateJar); err != nil { 650*333d2b36SAndroid Build Coastguard Worker return err 651*333d2b36SAndroid Build Coastguard Worker } 652*333d2b36SAndroid Build Coastguard Worker 653*333d2b36SAndroid Build Coastguard Worker if prev, exists := z.createdDirs[dest]; exists { 654*333d2b36SAndroid Build Coastguard Worker return fmt.Errorf("destination %q is both a directory %q and a file %q", dest, prev, src) 655*333d2b36SAndroid Build Coastguard Worker } 656*333d2b36SAndroid Build Coastguard Worker 657*333d2b36SAndroid Build Coastguard Worker return nil 658*333d2b36SAndroid Build Coastguard Worker } 659*333d2b36SAndroid Build Coastguard Worker 660*333d2b36SAndroid Build Coastguard Worker checkDuplicateFiles := func(dest, src string) (bool, error) { 661*333d2b36SAndroid Build Coastguard Worker if prev, exists := z.createdFiles[dest]; exists { 662*333d2b36SAndroid Build Coastguard Worker if prev != src { 663*333d2b36SAndroid Build Coastguard Worker return true, ConflictingFileError{ 664*333d2b36SAndroid Build Coastguard Worker Dest: dest, 665*333d2b36SAndroid Build Coastguard Worker Prev: prev, 666*333d2b36SAndroid Build Coastguard Worker Src: src, 667*333d2b36SAndroid Build Coastguard Worker } 668*333d2b36SAndroid Build Coastguard Worker } 669*333d2b36SAndroid Build Coastguard Worker return true, nil 670*333d2b36SAndroid Build Coastguard Worker } 671*333d2b36SAndroid Build Coastguard Worker 672*333d2b36SAndroid Build Coastguard Worker z.createdFiles[dest] = src 673*333d2b36SAndroid Build Coastguard Worker return false, nil 674*333d2b36SAndroid Build Coastguard Worker } 675*333d2b36SAndroid Build Coastguard Worker 676*333d2b36SAndroid Build Coastguard Worker if s.IsDir() { 677*333d2b36SAndroid Build Coastguard Worker if z.directories { 678*333d2b36SAndroid Build Coastguard Worker return z.writeDirectory(dest, src, emulateJar) 679*333d2b36SAndroid Build Coastguard Worker } 680*333d2b36SAndroid Build Coastguard Worker return nil 681*333d2b36SAndroid Build Coastguard Worker } else if s.Mode()&os.ModeSymlink != 0 { 682*333d2b36SAndroid Build Coastguard Worker err = createParentDirs(dest, src) 683*333d2b36SAndroid Build Coastguard Worker if err != nil { 684*333d2b36SAndroid Build Coastguard Worker return err 685*333d2b36SAndroid Build Coastguard Worker } 686*333d2b36SAndroid Build Coastguard Worker 687*333d2b36SAndroid Build Coastguard Worker duplicate, err := checkDuplicateFiles(dest, src) 688*333d2b36SAndroid Build Coastguard Worker if err != nil { 689*333d2b36SAndroid Build Coastguard Worker return err 690*333d2b36SAndroid Build Coastguard Worker } 691*333d2b36SAndroid Build Coastguard Worker if duplicate { 692*333d2b36SAndroid Build Coastguard Worker return nil 693*333d2b36SAndroid Build Coastguard Worker } 694*333d2b36SAndroid Build Coastguard Worker 695*333d2b36SAndroid Build Coastguard Worker return z.writeSymlink(dest, src) 696*333d2b36SAndroid Build Coastguard Worker } else if s.Mode().IsRegular() { 697*333d2b36SAndroid Build Coastguard Worker r, err := z.fs.Open(src) 698*333d2b36SAndroid Build Coastguard Worker if err != nil { 699*333d2b36SAndroid Build Coastguard Worker return err 700*333d2b36SAndroid Build Coastguard Worker } 701*333d2b36SAndroid Build Coastguard Worker 702*333d2b36SAndroid Build Coastguard Worker if srcJar && filepath.Ext(src) == ".java" { 703*333d2b36SAndroid Build Coastguard Worker // rewrite the destination using the package path if it can be determined 704*333d2b36SAndroid Build Coastguard Worker pkg, err := jar.JavaPackage(r, src) 705*333d2b36SAndroid Build Coastguard Worker if err != nil { 706*333d2b36SAndroid Build Coastguard Worker // ignore errors for now, leaving the file at in its original location in the zip 707*333d2b36SAndroid Build Coastguard Worker } else { 708*333d2b36SAndroid Build Coastguard Worker dest = filepath.Join(filepath.Join(strings.Split(pkg, ".")...), filepath.Base(src)) 709*333d2b36SAndroid Build Coastguard Worker } 710*333d2b36SAndroid Build Coastguard Worker 711*333d2b36SAndroid Build Coastguard Worker _, err = r.Seek(0, io.SeekStart) 712*333d2b36SAndroid Build Coastguard Worker if err != nil { 713*333d2b36SAndroid Build Coastguard Worker return err 714*333d2b36SAndroid Build Coastguard Worker } 715*333d2b36SAndroid Build Coastguard Worker } 716*333d2b36SAndroid Build Coastguard Worker 717*333d2b36SAndroid Build Coastguard Worker fileSize = s.Size() 718*333d2b36SAndroid Build Coastguard Worker executable = s.Mode()&0100 != 0 719*333d2b36SAndroid Build Coastguard Worker 720*333d2b36SAndroid Build Coastguard Worker header := &zip.FileHeader{ 721*333d2b36SAndroid Build Coastguard Worker Name: dest, 722*333d2b36SAndroid Build Coastguard Worker Method: method, 723*333d2b36SAndroid Build Coastguard Worker UncompressedSize64: uint64(fileSize), 724*333d2b36SAndroid Build Coastguard Worker } 725*333d2b36SAndroid Build Coastguard Worker 726*333d2b36SAndroid Build Coastguard Worker mode := os.FileMode(0644) 727*333d2b36SAndroid Build Coastguard Worker if executable { 728*333d2b36SAndroid Build Coastguard Worker mode = 0755 729*333d2b36SAndroid Build Coastguard Worker } 730*333d2b36SAndroid Build Coastguard Worker header.SetMode(mode) 731*333d2b36SAndroid Build Coastguard Worker 732*333d2b36SAndroid Build Coastguard Worker err = createParentDirs(dest, src) 733*333d2b36SAndroid Build Coastguard Worker if err != nil { 734*333d2b36SAndroid Build Coastguard Worker return err 735*333d2b36SAndroid Build Coastguard Worker } 736*333d2b36SAndroid Build Coastguard Worker 737*333d2b36SAndroid Build Coastguard Worker duplicate, err := checkDuplicateFiles(dest, src) 738*333d2b36SAndroid Build Coastguard Worker if err != nil { 739*333d2b36SAndroid Build Coastguard Worker return err 740*333d2b36SAndroid Build Coastguard Worker } 741*333d2b36SAndroid Build Coastguard Worker if duplicate { 742*333d2b36SAndroid Build Coastguard Worker return nil 743*333d2b36SAndroid Build Coastguard Worker } 744*333d2b36SAndroid Build Coastguard Worker 745*333d2b36SAndroid Build Coastguard Worker return z.writeFileContents(header, r) 746*333d2b36SAndroid Build Coastguard Worker } else { 747*333d2b36SAndroid Build Coastguard Worker return fmt.Errorf("%s is not a file, directory, or symlink", src) 748*333d2b36SAndroid Build Coastguard Worker } 749*333d2b36SAndroid Build Coastguard Worker} 750*333d2b36SAndroid Build Coastguard Worker 751*333d2b36SAndroid Build Coastguard Workerfunc (z *ZipWriter) addManifest(dest string, src string, _ uint16) error { 752*333d2b36SAndroid Build Coastguard Worker if prev, exists := z.createdDirs[dest]; exists { 753*333d2b36SAndroid Build Coastguard Worker return fmt.Errorf("destination %q is both a directory %q and a file %q", dest, prev, src) 754*333d2b36SAndroid Build Coastguard Worker } 755*333d2b36SAndroid Build Coastguard Worker if prev, exists := z.createdFiles[dest]; exists { 756*333d2b36SAndroid Build Coastguard Worker if prev != src { 757*333d2b36SAndroid Build Coastguard Worker return ConflictingFileError{ 758*333d2b36SAndroid Build Coastguard Worker Dest: dest, 759*333d2b36SAndroid Build Coastguard Worker Prev: prev, 760*333d2b36SAndroid Build Coastguard Worker Src: src, 761*333d2b36SAndroid Build Coastguard Worker } 762*333d2b36SAndroid Build Coastguard Worker } 763*333d2b36SAndroid Build Coastguard Worker return nil 764*333d2b36SAndroid Build Coastguard Worker } 765*333d2b36SAndroid Build Coastguard Worker 766*333d2b36SAndroid Build Coastguard Worker if err := z.writeDirectory(filepath.Dir(dest), src, true); err != nil { 767*333d2b36SAndroid Build Coastguard Worker return err 768*333d2b36SAndroid Build Coastguard Worker } 769*333d2b36SAndroid Build Coastguard Worker 770*333d2b36SAndroid Build Coastguard Worker var contents []byte 771*333d2b36SAndroid Build Coastguard Worker if src != "" { 772*333d2b36SAndroid Build Coastguard Worker f, err := z.fs.Open(src) 773*333d2b36SAndroid Build Coastguard Worker if err != nil { 774*333d2b36SAndroid Build Coastguard Worker return err 775*333d2b36SAndroid Build Coastguard Worker } 776*333d2b36SAndroid Build Coastguard Worker 777*333d2b36SAndroid Build Coastguard Worker contents, err = ioutil.ReadAll(f) 778*333d2b36SAndroid Build Coastguard Worker f.Close() 779*333d2b36SAndroid Build Coastguard Worker if err != nil { 780*333d2b36SAndroid Build Coastguard Worker return err 781*333d2b36SAndroid Build Coastguard Worker } 782*333d2b36SAndroid Build Coastguard Worker } 783*333d2b36SAndroid Build Coastguard Worker 784*333d2b36SAndroid Build Coastguard Worker fh, buf, err := jar.ManifestFileContents(contents) 785*333d2b36SAndroid Build Coastguard Worker if err != nil { 786*333d2b36SAndroid Build Coastguard Worker return err 787*333d2b36SAndroid Build Coastguard Worker } 788*333d2b36SAndroid Build Coastguard Worker 789*333d2b36SAndroid Build Coastguard Worker reader := &byteReaderCloser{bytes.NewReader(buf), ioutil.NopCloser(nil)} 790*333d2b36SAndroid Build Coastguard Worker 791*333d2b36SAndroid Build Coastguard Worker return z.writeFileContents(fh, reader) 792*333d2b36SAndroid Build Coastguard Worker} 793*333d2b36SAndroid Build Coastguard Worker 794*333d2b36SAndroid Build Coastguard Workerfunc (z *ZipWriter) writeFileContents(header *zip.FileHeader, r pathtools.ReaderAtSeekerCloser) (err error) { 795*333d2b36SAndroid Build Coastguard Worker 796*333d2b36SAndroid Build Coastguard Worker header.SetModTime(z.time) 797*333d2b36SAndroid Build Coastguard Worker 798*333d2b36SAndroid Build Coastguard Worker compressChan := make(chan *zipEntry, 1) 799*333d2b36SAndroid Build Coastguard Worker z.writeOps <- compressChan 800*333d2b36SAndroid Build Coastguard Worker 801*333d2b36SAndroid Build Coastguard Worker // Pre-fill a zipEntry, it will be sent in the compressChan once 802*333d2b36SAndroid Build Coastguard Worker // we're sure about the Method and CRC. 803*333d2b36SAndroid Build Coastguard Worker ze := &zipEntry{ 804*333d2b36SAndroid Build Coastguard Worker fh: header, 805*333d2b36SAndroid Build Coastguard Worker } 806*333d2b36SAndroid Build Coastguard Worker 807*333d2b36SAndroid Build Coastguard Worker ze.allocatedSize = int64(header.UncompressedSize64) 808*333d2b36SAndroid Build Coastguard Worker z.cpuRateLimiter.Request() 809*333d2b36SAndroid Build Coastguard Worker z.memoryRateLimiter.Request(ze.allocatedSize) 810*333d2b36SAndroid Build Coastguard Worker 811*333d2b36SAndroid Build Coastguard Worker fileSize := int64(header.UncompressedSize64) 812*333d2b36SAndroid Build Coastguard Worker if fileSize == 0 { 813*333d2b36SAndroid Build Coastguard Worker fileSize = int64(header.UncompressedSize) 814*333d2b36SAndroid Build Coastguard Worker } 815*333d2b36SAndroid Build Coastguard Worker 816*333d2b36SAndroid Build Coastguard Worker if header.Method == zip.Deflate && fileSize >= minParallelFileSize { 817*333d2b36SAndroid Build Coastguard Worker wg := new(sync.WaitGroup) 818*333d2b36SAndroid Build Coastguard Worker 819*333d2b36SAndroid Build Coastguard Worker // Allocate enough buffer to hold all readers. We'll limit 820*333d2b36SAndroid Build Coastguard Worker // this based on actual buffer sizes in RateLimit. 821*333d2b36SAndroid Build Coastguard Worker ze.futureReaders = make(chan chan io.Reader, (fileSize/parallelBlockSize)+1) 822*333d2b36SAndroid Build Coastguard Worker 823*333d2b36SAndroid Build Coastguard Worker // Calculate the CRC and SHA256 in the background, since reading 824*333d2b36SAndroid Build Coastguard Worker // the entire file could take a while. 825*333d2b36SAndroid Build Coastguard Worker // 826*333d2b36SAndroid Build Coastguard Worker // We could split this up into chunks as well, but it's faster 827*333d2b36SAndroid Build Coastguard Worker // than the compression. Due to the Go Zip API, we also need to 828*333d2b36SAndroid Build Coastguard Worker // know the result before we can begin writing the compressed 829*333d2b36SAndroid Build Coastguard Worker // data out to the zipfile. 830*333d2b36SAndroid Build Coastguard Worker // 831*333d2b36SAndroid Build Coastguard Worker // We calculate SHA256 only if `-sha256` is set. 832*333d2b36SAndroid Build Coastguard Worker wg.Add(1) 833*333d2b36SAndroid Build Coastguard Worker go z.checksumFileAsync(r, ze, compressChan, wg) 834*333d2b36SAndroid Build Coastguard Worker 835*333d2b36SAndroid Build Coastguard Worker for start := int64(0); start < fileSize; start += parallelBlockSize { 836*333d2b36SAndroid Build Coastguard Worker sr := io.NewSectionReader(r, start, parallelBlockSize) 837*333d2b36SAndroid Build Coastguard Worker resultChan := make(chan io.Reader, 1) 838*333d2b36SAndroid Build Coastguard Worker ze.futureReaders <- resultChan 839*333d2b36SAndroid Build Coastguard Worker 840*333d2b36SAndroid Build Coastguard Worker z.cpuRateLimiter.Request() 841*333d2b36SAndroid Build Coastguard Worker 842*333d2b36SAndroid Build Coastguard Worker last := !(start+parallelBlockSize < fileSize) 843*333d2b36SAndroid Build Coastguard Worker var dict []byte 844*333d2b36SAndroid Build Coastguard Worker if start >= windowSize { 845*333d2b36SAndroid Build Coastguard Worker dict, err = ioutil.ReadAll(io.NewSectionReader(r, start-windowSize, windowSize)) 846*333d2b36SAndroid Build Coastguard Worker if err != nil { 847*333d2b36SAndroid Build Coastguard Worker return err 848*333d2b36SAndroid Build Coastguard Worker } 849*333d2b36SAndroid Build Coastguard Worker } 850*333d2b36SAndroid Build Coastguard Worker 851*333d2b36SAndroid Build Coastguard Worker wg.Add(1) 852*333d2b36SAndroid Build Coastguard Worker go z.compressPartialFile(sr, dict, last, resultChan, wg) 853*333d2b36SAndroid Build Coastguard Worker } 854*333d2b36SAndroid Build Coastguard Worker 855*333d2b36SAndroid Build Coastguard Worker close(ze.futureReaders) 856*333d2b36SAndroid Build Coastguard Worker 857*333d2b36SAndroid Build Coastguard Worker // Close the file handle after all readers are done 858*333d2b36SAndroid Build Coastguard Worker go func(wg *sync.WaitGroup, closer io.Closer) { 859*333d2b36SAndroid Build Coastguard Worker wg.Wait() 860*333d2b36SAndroid Build Coastguard Worker closer.Close() 861*333d2b36SAndroid Build Coastguard Worker }(wg, r) 862*333d2b36SAndroid Build Coastguard Worker } else { 863*333d2b36SAndroid Build Coastguard Worker go func() { 864*333d2b36SAndroid Build Coastguard Worker z.compressWholeFile(ze, r, compressChan) 865*333d2b36SAndroid Build Coastguard Worker r.Close() 866*333d2b36SAndroid Build Coastguard Worker }() 867*333d2b36SAndroid Build Coastguard Worker } 868*333d2b36SAndroid Build Coastguard Worker 869*333d2b36SAndroid Build Coastguard Worker return nil 870*333d2b36SAndroid Build Coastguard Worker} 871*333d2b36SAndroid Build Coastguard Worker 872*333d2b36SAndroid Build Coastguard Workerfunc (z *ZipWriter) checksumFileAsync(r io.ReadSeeker, ze *zipEntry, resultChan chan *zipEntry, wg *sync.WaitGroup) { 873*333d2b36SAndroid Build Coastguard Worker defer wg.Done() 874*333d2b36SAndroid Build Coastguard Worker defer z.cpuRateLimiter.Finish() 875*333d2b36SAndroid Build Coastguard Worker 876*333d2b36SAndroid Build Coastguard Worker z.checksumFile(r, ze) 877*333d2b36SAndroid Build Coastguard Worker 878*333d2b36SAndroid Build Coastguard Worker resultChan <- ze 879*333d2b36SAndroid Build Coastguard Worker close(resultChan) 880*333d2b36SAndroid Build Coastguard Worker} 881*333d2b36SAndroid Build Coastguard Worker 882*333d2b36SAndroid Build Coastguard Workerfunc (z *ZipWriter) checksumFile(r io.ReadSeeker, ze *zipEntry) { 883*333d2b36SAndroid Build Coastguard Worker crc := crc32.NewIEEE() 884*333d2b36SAndroid Build Coastguard Worker writers := []io.Writer{crc} 885*333d2b36SAndroid Build Coastguard Worker 886*333d2b36SAndroid Build Coastguard Worker var shaHasher hash.Hash 887*333d2b36SAndroid Build Coastguard Worker if z.sha256Checksum && !ze.fh.Mode().IsDir() { 888*333d2b36SAndroid Build Coastguard Worker shaHasher = sha256.New() 889*333d2b36SAndroid Build Coastguard Worker writers = append(writers, shaHasher) 890*333d2b36SAndroid Build Coastguard Worker } 891*333d2b36SAndroid Build Coastguard Worker 892*333d2b36SAndroid Build Coastguard Worker w := io.MultiWriter(writers...) 893*333d2b36SAndroid Build Coastguard Worker 894*333d2b36SAndroid Build Coastguard Worker _, err := io.Copy(w, r) 895*333d2b36SAndroid Build Coastguard Worker if err != nil { 896*333d2b36SAndroid Build Coastguard Worker z.errors <- err 897*333d2b36SAndroid Build Coastguard Worker return 898*333d2b36SAndroid Build Coastguard Worker } 899*333d2b36SAndroid Build Coastguard Worker 900*333d2b36SAndroid Build Coastguard Worker ze.fh.CRC32 = crc.Sum32() 901*333d2b36SAndroid Build Coastguard Worker if shaHasher != nil { 902*333d2b36SAndroid Build Coastguard Worker z.appendSHAToExtra(ze, shaHasher.Sum(nil)) 903*333d2b36SAndroid Build Coastguard Worker } 904*333d2b36SAndroid Build Coastguard Worker} 905*333d2b36SAndroid Build Coastguard Worker 906*333d2b36SAndroid Build Coastguard Workerfunc (z *ZipWriter) appendSHAToExtra(ze *zipEntry, checksum []byte) { 907*333d2b36SAndroid Build Coastguard Worker // The block of SHA256 checksum consist of: 908*333d2b36SAndroid Build Coastguard Worker // - Header ID, equals to Sha256HeaderID (2 bytes) 909*333d2b36SAndroid Build Coastguard Worker // - Data size (2 bytes) 910*333d2b36SAndroid Build Coastguard Worker // - Data block: 911*333d2b36SAndroid Build Coastguard Worker // - Signature, equals to Sha256HeaderSignature (2 bytes) 912*333d2b36SAndroid Build Coastguard Worker // - Data, SHA checksum value 913*333d2b36SAndroid Build Coastguard Worker var buf []byte 914*333d2b36SAndroid Build Coastguard Worker buf = binary.LittleEndian.AppendUint16(buf, Sha256HeaderID) 915*333d2b36SAndroid Build Coastguard Worker buf = binary.LittleEndian.AppendUint16(buf, uint16(len(checksum)+2)) 916*333d2b36SAndroid Build Coastguard Worker buf = binary.LittleEndian.AppendUint16(buf, Sha256HeaderSignature) 917*333d2b36SAndroid Build Coastguard Worker buf = append(buf, checksum...) 918*333d2b36SAndroid Build Coastguard Worker ze.fh.Extra = append(ze.fh.Extra, buf...) 919*333d2b36SAndroid Build Coastguard Worker} 920*333d2b36SAndroid Build Coastguard Worker 921*333d2b36SAndroid Build Coastguard Workerfunc (z *ZipWriter) compressPartialFile(r io.Reader, dict []byte, last bool, resultChan chan io.Reader, wg *sync.WaitGroup) { 922*333d2b36SAndroid Build Coastguard Worker defer wg.Done() 923*333d2b36SAndroid Build Coastguard Worker 924*333d2b36SAndroid Build Coastguard Worker result, err := z.compressBlock(r, dict, last) 925*333d2b36SAndroid Build Coastguard Worker if err != nil { 926*333d2b36SAndroid Build Coastguard Worker z.errors <- err 927*333d2b36SAndroid Build Coastguard Worker return 928*333d2b36SAndroid Build Coastguard Worker } 929*333d2b36SAndroid Build Coastguard Worker 930*333d2b36SAndroid Build Coastguard Worker z.cpuRateLimiter.Finish() 931*333d2b36SAndroid Build Coastguard Worker 932*333d2b36SAndroid Build Coastguard Worker resultChan <- result 933*333d2b36SAndroid Build Coastguard Worker} 934*333d2b36SAndroid Build Coastguard Worker 935*333d2b36SAndroid Build Coastguard Workerfunc (z *ZipWriter) compressBlock(r io.Reader, dict []byte, last bool) (*bytes.Buffer, error) { 936*333d2b36SAndroid Build Coastguard Worker buf := new(bytes.Buffer) 937*333d2b36SAndroid Build Coastguard Worker var fw *flate.Writer 938*333d2b36SAndroid Build Coastguard Worker var err error 939*333d2b36SAndroid Build Coastguard Worker if len(dict) > 0 { 940*333d2b36SAndroid Build Coastguard Worker // There's no way to Reset a Writer with a new dictionary, so 941*333d2b36SAndroid Build Coastguard Worker // don't use the Pool 942*333d2b36SAndroid Build Coastguard Worker fw, err = flate.NewWriterDict(buf, z.compLevel, dict) 943*333d2b36SAndroid Build Coastguard Worker } else { 944*333d2b36SAndroid Build Coastguard Worker var ok bool 945*333d2b36SAndroid Build Coastguard Worker if fw, ok = z.compressorPool.Get().(*flate.Writer); ok { 946*333d2b36SAndroid Build Coastguard Worker fw.Reset(buf) 947*333d2b36SAndroid Build Coastguard Worker } else { 948*333d2b36SAndroid Build Coastguard Worker fw, err = flate.NewWriter(buf, z.compLevel) 949*333d2b36SAndroid Build Coastguard Worker } 950*333d2b36SAndroid Build Coastguard Worker defer z.compressorPool.Put(fw) 951*333d2b36SAndroid Build Coastguard Worker } 952*333d2b36SAndroid Build Coastguard Worker if err != nil { 953*333d2b36SAndroid Build Coastguard Worker return nil, err 954*333d2b36SAndroid Build Coastguard Worker } 955*333d2b36SAndroid Build Coastguard Worker 956*333d2b36SAndroid Build Coastguard Worker _, err = io.Copy(fw, r) 957*333d2b36SAndroid Build Coastguard Worker if err != nil { 958*333d2b36SAndroid Build Coastguard Worker return nil, err 959*333d2b36SAndroid Build Coastguard Worker } 960*333d2b36SAndroid Build Coastguard Worker if last { 961*333d2b36SAndroid Build Coastguard Worker fw.Close() 962*333d2b36SAndroid Build Coastguard Worker } else { 963*333d2b36SAndroid Build Coastguard Worker fw.Flush() 964*333d2b36SAndroid Build Coastguard Worker } 965*333d2b36SAndroid Build Coastguard Worker 966*333d2b36SAndroid Build Coastguard Worker return buf, nil 967*333d2b36SAndroid Build Coastguard Worker} 968*333d2b36SAndroid Build Coastguard Worker 969*333d2b36SAndroid Build Coastguard Workerfunc (z *ZipWriter) compressWholeFile(ze *zipEntry, r io.ReadSeeker, compressChan chan *zipEntry) { 970*333d2b36SAndroid Build Coastguard Worker z.checksumFile(r, ze) 971*333d2b36SAndroid Build Coastguard Worker 972*333d2b36SAndroid Build Coastguard Worker _, err := r.Seek(0, 0) 973*333d2b36SAndroid Build Coastguard Worker if err != nil { 974*333d2b36SAndroid Build Coastguard Worker z.errors <- err 975*333d2b36SAndroid Build Coastguard Worker return 976*333d2b36SAndroid Build Coastguard Worker } 977*333d2b36SAndroid Build Coastguard Worker 978*333d2b36SAndroid Build Coastguard Worker readFile := func(reader io.ReadSeeker) ([]byte, error) { 979*333d2b36SAndroid Build Coastguard Worker _, err := reader.Seek(0, 0) 980*333d2b36SAndroid Build Coastguard Worker if err != nil { 981*333d2b36SAndroid Build Coastguard Worker return nil, err 982*333d2b36SAndroid Build Coastguard Worker } 983*333d2b36SAndroid Build Coastguard Worker 984*333d2b36SAndroid Build Coastguard Worker buf, err := ioutil.ReadAll(reader) 985*333d2b36SAndroid Build Coastguard Worker if err != nil { 986*333d2b36SAndroid Build Coastguard Worker return nil, err 987*333d2b36SAndroid Build Coastguard Worker } 988*333d2b36SAndroid Build Coastguard Worker 989*333d2b36SAndroid Build Coastguard Worker return buf, nil 990*333d2b36SAndroid Build Coastguard Worker } 991*333d2b36SAndroid Build Coastguard Worker 992*333d2b36SAndroid Build Coastguard Worker ze.futureReaders = make(chan chan io.Reader, 1) 993*333d2b36SAndroid Build Coastguard Worker futureReader := make(chan io.Reader, 1) 994*333d2b36SAndroid Build Coastguard Worker ze.futureReaders <- futureReader 995*333d2b36SAndroid Build Coastguard Worker close(ze.futureReaders) 996*333d2b36SAndroid Build Coastguard Worker 997*333d2b36SAndroid Build Coastguard Worker if ze.fh.Method == zip.Deflate { 998*333d2b36SAndroid Build Coastguard Worker compressed, err := z.compressBlock(r, nil, true) 999*333d2b36SAndroid Build Coastguard Worker if err != nil { 1000*333d2b36SAndroid Build Coastguard Worker z.errors <- err 1001*333d2b36SAndroid Build Coastguard Worker return 1002*333d2b36SAndroid Build Coastguard Worker } 1003*333d2b36SAndroid Build Coastguard Worker if uint64(compressed.Len()) < ze.fh.UncompressedSize64 { 1004*333d2b36SAndroid Build Coastguard Worker futureReader <- compressed 1005*333d2b36SAndroid Build Coastguard Worker } else { 1006*333d2b36SAndroid Build Coastguard Worker buf, err := readFile(r) 1007*333d2b36SAndroid Build Coastguard Worker if err != nil { 1008*333d2b36SAndroid Build Coastguard Worker z.errors <- err 1009*333d2b36SAndroid Build Coastguard Worker return 1010*333d2b36SAndroid Build Coastguard Worker } 1011*333d2b36SAndroid Build Coastguard Worker ze.fh.Method = zip.Store 1012*333d2b36SAndroid Build Coastguard Worker futureReader <- bytes.NewReader(buf) 1013*333d2b36SAndroid Build Coastguard Worker } 1014*333d2b36SAndroid Build Coastguard Worker } else { 1015*333d2b36SAndroid Build Coastguard Worker buf, err := readFile(r) 1016*333d2b36SAndroid Build Coastguard Worker if err != nil { 1017*333d2b36SAndroid Build Coastguard Worker z.errors <- err 1018*333d2b36SAndroid Build Coastguard Worker return 1019*333d2b36SAndroid Build Coastguard Worker } 1020*333d2b36SAndroid Build Coastguard Worker ze.fh.Method = zip.Store 1021*333d2b36SAndroid Build Coastguard Worker futureReader <- bytes.NewReader(buf) 1022*333d2b36SAndroid Build Coastguard Worker } 1023*333d2b36SAndroid Build Coastguard Worker 1024*333d2b36SAndroid Build Coastguard Worker z.cpuRateLimiter.Finish() 1025*333d2b36SAndroid Build Coastguard Worker 1026*333d2b36SAndroid Build Coastguard Worker close(futureReader) 1027*333d2b36SAndroid Build Coastguard Worker 1028*333d2b36SAndroid Build Coastguard Worker compressChan <- ze 1029*333d2b36SAndroid Build Coastguard Worker close(compressChan) 1030*333d2b36SAndroid Build Coastguard Worker} 1031*333d2b36SAndroid Build Coastguard Worker 1032*333d2b36SAndroid Build Coastguard Worker// writeDirectory annotates that dir is a directory created for the src file or directory, and adds 1033*333d2b36SAndroid Build Coastguard Worker// the directory entry to the zip file if directories are enabled. 1034*333d2b36SAndroid Build Coastguard Workerfunc (z *ZipWriter) writeDirectory(dir string, src string, emulateJar bool) error { 1035*333d2b36SAndroid Build Coastguard Worker // clean the input 1036*333d2b36SAndroid Build Coastguard Worker dir = filepath.Clean(dir) 1037*333d2b36SAndroid Build Coastguard Worker 1038*333d2b36SAndroid Build Coastguard Worker // discover any uncreated directories in the path 1039*333d2b36SAndroid Build Coastguard Worker var zipDirs []string 1040*333d2b36SAndroid Build Coastguard Worker for dir != "" && dir != "." { 1041*333d2b36SAndroid Build Coastguard Worker if _, exists := z.createdDirs[dir]; exists { 1042*333d2b36SAndroid Build Coastguard Worker break 1043*333d2b36SAndroid Build Coastguard Worker } 1044*333d2b36SAndroid Build Coastguard Worker 1045*333d2b36SAndroid Build Coastguard Worker if prev, exists := z.createdFiles[dir]; exists { 1046*333d2b36SAndroid Build Coastguard Worker return fmt.Errorf("destination %q is both a directory %q and a file %q", dir, src, prev) 1047*333d2b36SAndroid Build Coastguard Worker } 1048*333d2b36SAndroid Build Coastguard Worker 1049*333d2b36SAndroid Build Coastguard Worker z.createdDirs[dir] = src 1050*333d2b36SAndroid Build Coastguard Worker // parent directories precede their children 1051*333d2b36SAndroid Build Coastguard Worker zipDirs = append([]string{dir}, zipDirs...) 1052*333d2b36SAndroid Build Coastguard Worker 1053*333d2b36SAndroid Build Coastguard Worker dir = filepath.Dir(dir) 1054*333d2b36SAndroid Build Coastguard Worker } 1055*333d2b36SAndroid Build Coastguard Worker 1056*333d2b36SAndroid Build Coastguard Worker if z.directories { 1057*333d2b36SAndroid Build Coastguard Worker // make a directory entry for each uncreated directory 1058*333d2b36SAndroid Build Coastguard Worker for _, cleanDir := range zipDirs { 1059*333d2b36SAndroid Build Coastguard Worker var dirHeader *zip.FileHeader 1060*333d2b36SAndroid Build Coastguard Worker 1061*333d2b36SAndroid Build Coastguard Worker if emulateJar && cleanDir+"/" == jar.MetaDir { 1062*333d2b36SAndroid Build Coastguard Worker dirHeader = jar.MetaDirFileHeader() 1063*333d2b36SAndroid Build Coastguard Worker } else { 1064*333d2b36SAndroid Build Coastguard Worker dirHeader = &zip.FileHeader{ 1065*333d2b36SAndroid Build Coastguard Worker Name: cleanDir + "/", 1066*333d2b36SAndroid Build Coastguard Worker } 1067*333d2b36SAndroid Build Coastguard Worker dirHeader.SetMode(0755 | os.ModeDir) 1068*333d2b36SAndroid Build Coastguard Worker } 1069*333d2b36SAndroid Build Coastguard Worker 1070*333d2b36SAndroid Build Coastguard Worker dirHeader.SetModTime(z.time) 1071*333d2b36SAndroid Build Coastguard Worker 1072*333d2b36SAndroid Build Coastguard Worker ze := make(chan *zipEntry, 1) 1073*333d2b36SAndroid Build Coastguard Worker ze <- &zipEntry{ 1074*333d2b36SAndroid Build Coastguard Worker fh: dirHeader, 1075*333d2b36SAndroid Build Coastguard Worker } 1076*333d2b36SAndroid Build Coastguard Worker close(ze) 1077*333d2b36SAndroid Build Coastguard Worker z.writeOps <- ze 1078*333d2b36SAndroid Build Coastguard Worker } 1079*333d2b36SAndroid Build Coastguard Worker } 1080*333d2b36SAndroid Build Coastguard Worker 1081*333d2b36SAndroid Build Coastguard Worker return nil 1082*333d2b36SAndroid Build Coastguard Worker} 1083*333d2b36SAndroid Build Coastguard Worker 1084*333d2b36SAndroid Build Coastguard Workerfunc (z *ZipWriter) writeSymlink(rel, file string) error { 1085*333d2b36SAndroid Build Coastguard Worker fileHeader := &zip.FileHeader{ 1086*333d2b36SAndroid Build Coastguard Worker Name: rel, 1087*333d2b36SAndroid Build Coastguard Worker } 1088*333d2b36SAndroid Build Coastguard Worker fileHeader.SetModTime(z.time) 1089*333d2b36SAndroid Build Coastguard Worker fileHeader.SetMode(0777 | os.ModeSymlink) 1090*333d2b36SAndroid Build Coastguard Worker 1091*333d2b36SAndroid Build Coastguard Worker dest, err := z.fs.Readlink(file) 1092*333d2b36SAndroid Build Coastguard Worker if err != nil { 1093*333d2b36SAndroid Build Coastguard Worker return err 1094*333d2b36SAndroid Build Coastguard Worker } 1095*333d2b36SAndroid Build Coastguard Worker 1096*333d2b36SAndroid Build Coastguard Worker fileHeader.UncompressedSize64 = uint64(len(dest)) 1097*333d2b36SAndroid Build Coastguard Worker fileHeader.CRC32 = crc32.ChecksumIEEE([]byte(dest)) 1098*333d2b36SAndroid Build Coastguard Worker 1099*333d2b36SAndroid Build Coastguard Worker ze := make(chan *zipEntry, 1) 1100*333d2b36SAndroid Build Coastguard Worker futureReaders := make(chan chan io.Reader, 1) 1101*333d2b36SAndroid Build Coastguard Worker futureReader := make(chan io.Reader, 1) 1102*333d2b36SAndroid Build Coastguard Worker futureReaders <- futureReader 1103*333d2b36SAndroid Build Coastguard Worker close(futureReaders) 1104*333d2b36SAndroid Build Coastguard Worker futureReader <- bytes.NewBufferString(dest) 1105*333d2b36SAndroid Build Coastguard Worker close(futureReader) 1106*333d2b36SAndroid Build Coastguard Worker 1107*333d2b36SAndroid Build Coastguard Worker ze <- &zipEntry{ 1108*333d2b36SAndroid Build Coastguard Worker fh: fileHeader, 1109*333d2b36SAndroid Build Coastguard Worker futureReaders: futureReaders, 1110*333d2b36SAndroid Build Coastguard Worker } 1111*333d2b36SAndroid Build Coastguard Worker close(ze) 1112*333d2b36SAndroid Build Coastguard Worker z.writeOps <- ze 1113*333d2b36SAndroid Build Coastguard Worker 1114*333d2b36SAndroid Build Coastguard Worker return nil 1115*333d2b36SAndroid Build Coastguard Worker} 1116