1*333d2b36SAndroid Build Coastguard Worker// Copyright 2016 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 "errors" 19*333d2b36SAndroid Build Coastguard Worker "io" 20*333d2b36SAndroid Build Coastguard Worker) 21*333d2b36SAndroid Build Coastguard Worker 22*333d2b36SAndroid Build Coastguard Workerconst DataDescriptorFlag = 0x8 23*333d2b36SAndroid Build Coastguard Workerconst ExtendedTimeStampTag = 0x5455 24*333d2b36SAndroid Build Coastguard Worker 25*333d2b36SAndroid Build Coastguard Workerfunc (w *Writer) CopyFrom(orig *File, newName string) error { 26*333d2b36SAndroid Build Coastguard Worker if w.last != nil && !w.last.closed { 27*333d2b36SAndroid Build Coastguard Worker if err := w.last.close(); err != nil { 28*333d2b36SAndroid Build Coastguard Worker return err 29*333d2b36SAndroid Build Coastguard Worker } 30*333d2b36SAndroid Build Coastguard Worker w.last = nil 31*333d2b36SAndroid Build Coastguard Worker } 32*333d2b36SAndroid Build Coastguard Worker 33*333d2b36SAndroid Build Coastguard Worker fileHeader := orig.FileHeader 34*333d2b36SAndroid Build Coastguard Worker fileHeader.Name = newName 35*333d2b36SAndroid Build Coastguard Worker fh := &fileHeader 36*333d2b36SAndroid Build Coastguard Worker 37*333d2b36SAndroid Build Coastguard Worker // In some cases, we need strip the extras if it change between Central Directory 38*333d2b36SAndroid Build Coastguard Worker // and Local File Header. 39*333d2b36SAndroid Build Coastguard Worker fh.Extra = stripExtras(fh.Extra) 40*333d2b36SAndroid Build Coastguard Worker 41*333d2b36SAndroid Build Coastguard Worker h := &header{ 42*333d2b36SAndroid Build Coastguard Worker FileHeader: fh, 43*333d2b36SAndroid Build Coastguard Worker offset: uint64(w.cw.count), 44*333d2b36SAndroid Build Coastguard Worker } 45*333d2b36SAndroid Build Coastguard Worker w.dir = append(w.dir, h) 46*333d2b36SAndroid Build Coastguard Worker if !fh.isZip64() { 47*333d2b36SAndroid Build Coastguard Worker // Some writers will generate 64 bit sizes and set 32 bit fields to 48*333d2b36SAndroid Build Coastguard Worker // uint32max even if the actual size fits in 32 bit. So we should 49*333d2b36SAndroid Build Coastguard Worker // make sure CompressedSize contains the correct value in such 50*333d2b36SAndroid Build Coastguard Worker // cases. With out the two lines below we would be writing invalid(-1) 51*333d2b36SAndroid Build Coastguard Worker // sizes in such case. 52*333d2b36SAndroid Build Coastguard Worker fh.CompressedSize = uint32(fh.CompressedSize64) 53*333d2b36SAndroid Build Coastguard Worker fh.UncompressedSize = uint32(fh.UncompressedSize64) 54*333d2b36SAndroid Build Coastguard Worker } 55*333d2b36SAndroid Build Coastguard Worker 56*333d2b36SAndroid Build Coastguard Worker if err := writeHeader(w.cw, fh); err != nil { 57*333d2b36SAndroid Build Coastguard Worker return err 58*333d2b36SAndroid Build Coastguard Worker } 59*333d2b36SAndroid Build Coastguard Worker 60*333d2b36SAndroid Build Coastguard Worker // Strip the extras again in case writeHeader added the local file header extras that are incorrect for the 61*333d2b36SAndroid Build Coastguard Worker // central directory. 62*333d2b36SAndroid Build Coastguard Worker fh.Extra = stripExtras(fh.Extra) 63*333d2b36SAndroid Build Coastguard Worker 64*333d2b36SAndroid Build Coastguard Worker dataOffset, err := orig.DataOffset() 65*333d2b36SAndroid Build Coastguard Worker if err != nil { 66*333d2b36SAndroid Build Coastguard Worker return err 67*333d2b36SAndroid Build Coastguard Worker } 68*333d2b36SAndroid Build Coastguard Worker io.Copy(w.cw, io.NewSectionReader(orig.zipr, dataOffset, int64(orig.CompressedSize64))) 69*333d2b36SAndroid Build Coastguard Worker 70*333d2b36SAndroid Build Coastguard Worker if orig.hasDataDescriptor() { 71*333d2b36SAndroid Build Coastguard Worker // Write data descriptor. 72*333d2b36SAndroid Build Coastguard Worker var buf []byte 73*333d2b36SAndroid Build Coastguard Worker if fh.isZip64() { 74*333d2b36SAndroid Build Coastguard Worker buf = make([]byte, dataDescriptor64Len) 75*333d2b36SAndroid Build Coastguard Worker } else { 76*333d2b36SAndroid Build Coastguard Worker buf = make([]byte, dataDescriptorLen) 77*333d2b36SAndroid Build Coastguard Worker } 78*333d2b36SAndroid Build Coastguard Worker b := writeBuf(buf) 79*333d2b36SAndroid Build Coastguard Worker b.uint32(dataDescriptorSignature) 80*333d2b36SAndroid Build Coastguard Worker b.uint32(fh.CRC32) 81*333d2b36SAndroid Build Coastguard Worker if fh.isZip64() { 82*333d2b36SAndroid Build Coastguard Worker b.uint64(fh.CompressedSize64) 83*333d2b36SAndroid Build Coastguard Worker b.uint64(fh.UncompressedSize64) 84*333d2b36SAndroid Build Coastguard Worker } else { 85*333d2b36SAndroid Build Coastguard Worker b.uint32(fh.CompressedSize) 86*333d2b36SAndroid Build Coastguard Worker b.uint32(fh.UncompressedSize) 87*333d2b36SAndroid Build Coastguard Worker } 88*333d2b36SAndroid Build Coastguard Worker _, err = w.cw.Write(buf) 89*333d2b36SAndroid Build Coastguard Worker } 90*333d2b36SAndroid Build Coastguard Worker return err 91*333d2b36SAndroid Build Coastguard Worker} 92*333d2b36SAndroid Build Coastguard Worker 93*333d2b36SAndroid Build Coastguard Worker// The zip64 extras change between the Central Directory and Local File Header, while we use 94*333d2b36SAndroid Build Coastguard Worker// the same structure for both. The Local File Haeder is taken care of by us writing a data 95*333d2b36SAndroid Build Coastguard Worker// descriptor with the zip64 values. The Central Directory Entry is written by Close(), where 96*333d2b36SAndroid Build Coastguard Worker// the zip64 extra is automatically created and appended when necessary. 97*333d2b36SAndroid Build Coastguard Worker// 98*333d2b36SAndroid Build Coastguard Worker// The extended-timestamp extra block changes between the Central Directory Header and Local 99*333d2b36SAndroid Build Coastguard Worker// File Header. 100*333d2b36SAndroid Build Coastguard Worker// Extended-Timestamp extra(LFH): <tag-size-flag-modtime-actime-changetime> 101*333d2b36SAndroid Build Coastguard Worker// Extended-Timestamp extra(CDH): <tag-size-flag-modtime> 102*333d2b36SAndroid Build Coastguard Workerfunc stripExtras(input []byte) []byte { 103*333d2b36SAndroid Build Coastguard Worker ret := []byte{} 104*333d2b36SAndroid Build Coastguard Worker 105*333d2b36SAndroid Build Coastguard Worker for len(input) >= 4 { 106*333d2b36SAndroid Build Coastguard Worker r := readBuf(input) 107*333d2b36SAndroid Build Coastguard Worker tag := r.uint16() 108*333d2b36SAndroid Build Coastguard Worker size := r.uint16() 109*333d2b36SAndroid Build Coastguard Worker if int(size) > len(r) { 110*333d2b36SAndroid Build Coastguard Worker break 111*333d2b36SAndroid Build Coastguard Worker } 112*333d2b36SAndroid Build Coastguard Worker if tag != zip64ExtraId && tag != ExtendedTimeStampTag { 113*333d2b36SAndroid Build Coastguard Worker ret = append(ret, input[:4+size]...) 114*333d2b36SAndroid Build Coastguard Worker } 115*333d2b36SAndroid Build Coastguard Worker input = input[4+size:] 116*333d2b36SAndroid Build Coastguard Worker } 117*333d2b36SAndroid Build Coastguard Worker 118*333d2b36SAndroid Build Coastguard Worker // Keep any trailing data 119*333d2b36SAndroid Build Coastguard Worker ret = append(ret, input...) 120*333d2b36SAndroid Build Coastguard Worker 121*333d2b36SAndroid Build Coastguard Worker return ret 122*333d2b36SAndroid Build Coastguard Worker} 123*333d2b36SAndroid Build Coastguard Worker 124*333d2b36SAndroid Build Coastguard Worker// CreateCompressedHeader adds a file to the zip file using the provied 125*333d2b36SAndroid Build Coastguard Worker// FileHeader for the file metadata. 126*333d2b36SAndroid Build Coastguard Worker// It returns a Writer to which the already compressed file contents 127*333d2b36SAndroid Build Coastguard Worker// should be written. 128*333d2b36SAndroid Build Coastguard Worker// 129*333d2b36SAndroid Build Coastguard Worker// The UncompressedSize64 and CRC32 entries in the FileHeader must be filled 130*333d2b36SAndroid Build Coastguard Worker// out already. 131*333d2b36SAndroid Build Coastguard Worker// 132*333d2b36SAndroid Build Coastguard Worker// The file's contents must be written to the io.Writer before the next 133*333d2b36SAndroid Build Coastguard Worker// call to Create, CreateHeader, CreateCompressedHeader, or Close. The 134*333d2b36SAndroid Build Coastguard Worker// provided FileHeader fh must not be modified after a call to 135*333d2b36SAndroid Build Coastguard Worker// CreateCompressedHeader 136*333d2b36SAndroid Build Coastguard Workerfunc (w *Writer) CreateCompressedHeader(fh *FileHeader) (io.WriteCloser, error) { 137*333d2b36SAndroid Build Coastguard Worker if w.last != nil && !w.last.closed { 138*333d2b36SAndroid Build Coastguard Worker if err := w.last.close(); err != nil { 139*333d2b36SAndroid Build Coastguard Worker return nil, err 140*333d2b36SAndroid Build Coastguard Worker } 141*333d2b36SAndroid Build Coastguard Worker } 142*333d2b36SAndroid Build Coastguard Worker if len(w.dir) > 0 && w.dir[len(w.dir)-1].FileHeader == fh { 143*333d2b36SAndroid Build Coastguard Worker // See https://golang.org/issue/11144 confusion. 144*333d2b36SAndroid Build Coastguard Worker return nil, errors.New("archive/zip: invalid duplicate FileHeader") 145*333d2b36SAndroid Build Coastguard Worker } 146*333d2b36SAndroid Build Coastguard Worker 147*333d2b36SAndroid Build Coastguard Worker fh.Flags |= DataDescriptorFlag // we will write a data descriptor 148*333d2b36SAndroid Build Coastguard Worker 149*333d2b36SAndroid Build Coastguard Worker fh.CreatorVersion = fh.CreatorVersion&0xff00 | zipVersion20 // preserve compatibility byte 150*333d2b36SAndroid Build Coastguard Worker fh.ReaderVersion = zipVersion20 151*333d2b36SAndroid Build Coastguard Worker 152*333d2b36SAndroid Build Coastguard Worker fw := &compressedFileWriter{ 153*333d2b36SAndroid Build Coastguard Worker fileWriter{ 154*333d2b36SAndroid Build Coastguard Worker zipw: w.cw, 155*333d2b36SAndroid Build Coastguard Worker compCount: &countWriter{w: w.cw}, 156*333d2b36SAndroid Build Coastguard Worker }, 157*333d2b36SAndroid Build Coastguard Worker } 158*333d2b36SAndroid Build Coastguard Worker 159*333d2b36SAndroid Build Coastguard Worker h := &header{ 160*333d2b36SAndroid Build Coastguard Worker FileHeader: fh, 161*333d2b36SAndroid Build Coastguard Worker offset: uint64(w.cw.count), 162*333d2b36SAndroid Build Coastguard Worker } 163*333d2b36SAndroid Build Coastguard Worker w.dir = append(w.dir, h) 164*333d2b36SAndroid Build Coastguard Worker fw.header = h 165*333d2b36SAndroid Build Coastguard Worker 166*333d2b36SAndroid Build Coastguard Worker if err := writeHeader(w.cw, fh); err != nil { 167*333d2b36SAndroid Build Coastguard Worker return nil, err 168*333d2b36SAndroid Build Coastguard Worker } 169*333d2b36SAndroid Build Coastguard Worker 170*333d2b36SAndroid Build Coastguard Worker w.last = &fw.fileWriter 171*333d2b36SAndroid Build Coastguard Worker return fw, nil 172*333d2b36SAndroid Build Coastguard Worker} 173*333d2b36SAndroid Build Coastguard Worker 174*333d2b36SAndroid Build Coastguard Worker// Updated version of CreateHeader that doesn't enforce writing a data descriptor 175*333d2b36SAndroid Build Coastguard Workerfunc (w *Writer) CreateHeaderAndroid(fh *FileHeader) (io.Writer, error) { 176*333d2b36SAndroid Build Coastguard Worker writeDataDescriptor := fh.Method != Store 177*333d2b36SAndroid Build Coastguard Worker if writeDataDescriptor { 178*333d2b36SAndroid Build Coastguard Worker fh.Flags |= DataDescriptorFlag 179*333d2b36SAndroid Build Coastguard Worker } else { 180*333d2b36SAndroid Build Coastguard Worker fh.Flags &= ^uint16(DataDescriptorFlag) 181*333d2b36SAndroid Build Coastguard Worker } 182*333d2b36SAndroid Build Coastguard Worker return w.createHeaderImpl(fh) 183*333d2b36SAndroid Build Coastguard Worker} 184*333d2b36SAndroid Build Coastguard Worker 185*333d2b36SAndroid Build Coastguard Workertype compressedFileWriter struct { 186*333d2b36SAndroid Build Coastguard Worker fileWriter 187*333d2b36SAndroid Build Coastguard Worker} 188*333d2b36SAndroid Build Coastguard Worker 189*333d2b36SAndroid Build Coastguard Workerfunc (w *compressedFileWriter) Write(p []byte) (int, error) { 190*333d2b36SAndroid Build Coastguard Worker if w.closed { 191*333d2b36SAndroid Build Coastguard Worker return 0, errors.New("zip: write to closed file") 192*333d2b36SAndroid Build Coastguard Worker } 193*333d2b36SAndroid Build Coastguard Worker return w.compCount.Write(p) 194*333d2b36SAndroid Build Coastguard Worker} 195*333d2b36SAndroid Build Coastguard Worker 196*333d2b36SAndroid Build Coastguard Workerfunc (w *compressedFileWriter) Close() error { 197*333d2b36SAndroid Build Coastguard Worker if w.closed { 198*333d2b36SAndroid Build Coastguard Worker return errors.New("zip: file closed twice") 199*333d2b36SAndroid Build Coastguard Worker } 200*333d2b36SAndroid Build Coastguard Worker w.closed = true 201*333d2b36SAndroid Build Coastguard Worker 202*333d2b36SAndroid Build Coastguard Worker // update FileHeader 203*333d2b36SAndroid Build Coastguard Worker fh := w.header.FileHeader 204*333d2b36SAndroid Build Coastguard Worker fh.CompressedSize64 = uint64(w.compCount.count) 205*333d2b36SAndroid Build Coastguard Worker 206*333d2b36SAndroid Build Coastguard Worker if fh.isZip64() { 207*333d2b36SAndroid Build Coastguard Worker fh.CompressedSize = uint32max 208*333d2b36SAndroid Build Coastguard Worker fh.UncompressedSize = uint32max 209*333d2b36SAndroid Build Coastguard Worker fh.ReaderVersion = zipVersion45 // requires 4.5 - File uses ZIP64 format extensions 210*333d2b36SAndroid Build Coastguard Worker } else { 211*333d2b36SAndroid Build Coastguard Worker fh.CompressedSize = uint32(fh.CompressedSize64) 212*333d2b36SAndroid Build Coastguard Worker fh.UncompressedSize = uint32(fh.UncompressedSize64) 213*333d2b36SAndroid Build Coastguard Worker } 214*333d2b36SAndroid Build Coastguard Worker 215*333d2b36SAndroid Build Coastguard Worker // Write data descriptor. This is more complicated than one would 216*333d2b36SAndroid Build Coastguard Worker // think, see e.g. comments in zipfile.c:putextended() and 217*333d2b36SAndroid Build Coastguard Worker // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7073588. 218*333d2b36SAndroid Build Coastguard Worker // The approach here is to write 8 byte sizes if needed without 219*333d2b36SAndroid Build Coastguard Worker // adding a zip64 extra in the local header (too late anyway). 220*333d2b36SAndroid Build Coastguard Worker var buf []byte 221*333d2b36SAndroid Build Coastguard Worker if fh.isZip64() { 222*333d2b36SAndroid Build Coastguard Worker buf = make([]byte, dataDescriptor64Len) 223*333d2b36SAndroid Build Coastguard Worker } else { 224*333d2b36SAndroid Build Coastguard Worker buf = make([]byte, dataDescriptorLen) 225*333d2b36SAndroid Build Coastguard Worker } 226*333d2b36SAndroid Build Coastguard Worker b := writeBuf(buf) 227*333d2b36SAndroid Build Coastguard Worker b.uint32(dataDescriptorSignature) // de-facto standard, required by OS X 228*333d2b36SAndroid Build Coastguard Worker b.uint32(fh.CRC32) 229*333d2b36SAndroid Build Coastguard Worker if fh.isZip64() { 230*333d2b36SAndroid Build Coastguard Worker b.uint64(fh.CompressedSize64) 231*333d2b36SAndroid Build Coastguard Worker b.uint64(fh.UncompressedSize64) 232*333d2b36SAndroid Build Coastguard Worker } else { 233*333d2b36SAndroid Build Coastguard Worker b.uint32(fh.CompressedSize) 234*333d2b36SAndroid Build Coastguard Worker b.uint32(fh.UncompressedSize) 235*333d2b36SAndroid Build Coastguard Worker } 236*333d2b36SAndroid Build Coastguard Worker _, err := w.zipw.Write(buf) 237*333d2b36SAndroid Build Coastguard Worker return err 238*333d2b36SAndroid Build Coastguard Worker} 239