1*adcb0a62SAndroid Build Coastguard Worker /*
2*adcb0a62SAndroid Build Coastguard Worker * Copyright (C) 2015 The Android Open Source Project
3*adcb0a62SAndroid Build Coastguard Worker *
4*adcb0a62SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*adcb0a62SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*adcb0a62SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*adcb0a62SAndroid Build Coastguard Worker *
8*adcb0a62SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*adcb0a62SAndroid Build Coastguard Worker *
10*adcb0a62SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*adcb0a62SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*adcb0a62SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*adcb0a62SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*adcb0a62SAndroid Build Coastguard Worker * limitations under the License.
15*adcb0a62SAndroid Build Coastguard Worker */
16*adcb0a62SAndroid Build Coastguard Worker
17*adcb0a62SAndroid Build Coastguard Worker #define _POSIX_THREAD_SAFE_FUNCTIONS // For mingw localtime_r().
18*adcb0a62SAndroid Build Coastguard Worker
19*adcb0a62SAndroid Build Coastguard Worker #include "ziparchive/zip_writer.h"
20*adcb0a62SAndroid Build Coastguard Worker
21*adcb0a62SAndroid Build Coastguard Worker #include <sys/param.h>
22*adcb0a62SAndroid Build Coastguard Worker #include <sys/stat.h>
23*adcb0a62SAndroid Build Coastguard Worker #include <zlib.h>
24*adcb0a62SAndroid Build Coastguard Worker #include <cstdio>
25*adcb0a62SAndroid Build Coastguard Worker #define DEF_MEM_LEVEL 8 // normally in zutil.h?
26*adcb0a62SAndroid Build Coastguard Worker
27*adcb0a62SAndroid Build Coastguard Worker #include <memory>
28*adcb0a62SAndroid Build Coastguard Worker #include <vector>
29*adcb0a62SAndroid Build Coastguard Worker
30*adcb0a62SAndroid Build Coastguard Worker #include "android-base/logging.h"
31*adcb0a62SAndroid Build Coastguard Worker
32*adcb0a62SAndroid Build Coastguard Worker #include "entry_name_utils-inl.h"
33*adcb0a62SAndroid Build Coastguard Worker #include "zip_archive_common.h"
34*adcb0a62SAndroid Build Coastguard Worker
35*adcb0a62SAndroid Build Coastguard Worker #undef powerof2
36*adcb0a62SAndroid Build Coastguard Worker #define powerof2(x) \
37*adcb0a62SAndroid Build Coastguard Worker ({ \
38*adcb0a62SAndroid Build Coastguard Worker __typeof__(x) _x = (x); \
39*adcb0a62SAndroid Build Coastguard Worker __typeof__(x) _x2; \
40*adcb0a62SAndroid Build Coastguard Worker __builtin_add_overflow(_x, -1, &_x2) ? 1 : ((_x2 & _x) == 0); \
41*adcb0a62SAndroid Build Coastguard Worker })
42*adcb0a62SAndroid Build Coastguard Worker
43*adcb0a62SAndroid Build Coastguard Worker /* Zip compression methods we support */
44*adcb0a62SAndroid Build Coastguard Worker enum {
45*adcb0a62SAndroid Build Coastguard Worker kCompressStored = 0, // no compression
46*adcb0a62SAndroid Build Coastguard Worker kCompressDeflated = 8, // standard deflate
47*adcb0a62SAndroid Build Coastguard Worker };
48*adcb0a62SAndroid Build Coastguard Worker
49*adcb0a62SAndroid Build Coastguard Worker // Size of the output buffer used for compression.
50*adcb0a62SAndroid Build Coastguard Worker static const size_t kBufSize = 32768u;
51*adcb0a62SAndroid Build Coastguard Worker
52*adcb0a62SAndroid Build Coastguard Worker // No error, operation completed successfully.
53*adcb0a62SAndroid Build Coastguard Worker static const int32_t kNoError = 0;
54*adcb0a62SAndroid Build Coastguard Worker
55*adcb0a62SAndroid Build Coastguard Worker // The ZipWriter is in a bad state.
56*adcb0a62SAndroid Build Coastguard Worker static const int32_t kInvalidState = -1;
57*adcb0a62SAndroid Build Coastguard Worker
58*adcb0a62SAndroid Build Coastguard Worker // There was an IO error while writing to disk.
59*adcb0a62SAndroid Build Coastguard Worker static const int32_t kIoError = -2;
60*adcb0a62SAndroid Build Coastguard Worker
61*adcb0a62SAndroid Build Coastguard Worker // The zip entry name was invalid.
62*adcb0a62SAndroid Build Coastguard Worker static const int32_t kInvalidEntryName = -3;
63*adcb0a62SAndroid Build Coastguard Worker
64*adcb0a62SAndroid Build Coastguard Worker // An error occurred in zlib.
65*adcb0a62SAndroid Build Coastguard Worker static const int32_t kZlibError = -4;
66*adcb0a62SAndroid Build Coastguard Worker
67*adcb0a62SAndroid Build Coastguard Worker // The start aligned function was called with the aligned flag.
68*adcb0a62SAndroid Build Coastguard Worker static const int32_t kInvalidAlign32Flag = -5;
69*adcb0a62SAndroid Build Coastguard Worker
70*adcb0a62SAndroid Build Coastguard Worker // The alignment parameter is not a power of 2.
71*adcb0a62SAndroid Build Coastguard Worker static const int32_t kInvalidAlignment = -6;
72*adcb0a62SAndroid Build Coastguard Worker
73*adcb0a62SAndroid Build Coastguard Worker static const char* sErrorCodes[] = {
74*adcb0a62SAndroid Build Coastguard Worker "Invalid state", "IO error", "Invalid entry name", "Zlib error",
75*adcb0a62SAndroid Build Coastguard Worker };
76*adcb0a62SAndroid Build Coastguard Worker
ErrorCodeString(int32_t error_code)77*adcb0a62SAndroid Build Coastguard Worker const char* ZipWriter::ErrorCodeString(int32_t error_code) {
78*adcb0a62SAndroid Build Coastguard Worker if (error_code < 0 && (-error_code) < static_cast<int32_t>(arraysize(sErrorCodes))) {
79*adcb0a62SAndroid Build Coastguard Worker return sErrorCodes[-error_code];
80*adcb0a62SAndroid Build Coastguard Worker }
81*adcb0a62SAndroid Build Coastguard Worker return nullptr;
82*adcb0a62SAndroid Build Coastguard Worker }
83*adcb0a62SAndroid Build Coastguard Worker
DeleteZStream(z_stream * stream)84*adcb0a62SAndroid Build Coastguard Worker static void DeleteZStream(z_stream* stream) {
85*adcb0a62SAndroid Build Coastguard Worker deflateEnd(stream);
86*adcb0a62SAndroid Build Coastguard Worker delete stream;
87*adcb0a62SAndroid Build Coastguard Worker }
88*adcb0a62SAndroid Build Coastguard Worker
ZipWriter(FILE * f)89*adcb0a62SAndroid Build Coastguard Worker ZipWriter::ZipWriter(FILE* f)
90*adcb0a62SAndroid Build Coastguard Worker : file_(f),
91*adcb0a62SAndroid Build Coastguard Worker seekable_(false),
92*adcb0a62SAndroid Build Coastguard Worker current_offset_(0),
93*adcb0a62SAndroid Build Coastguard Worker state_(State::kWritingZip),
94*adcb0a62SAndroid Build Coastguard Worker z_stream_(nullptr, DeleteZStream),
95*adcb0a62SAndroid Build Coastguard Worker buffer_(kBufSize) {
96*adcb0a62SAndroid Build Coastguard Worker // Check if the file is seekable (regular file). If fstat fails, that's fine, subsequent calls
97*adcb0a62SAndroid Build Coastguard Worker // will fail as well.
98*adcb0a62SAndroid Build Coastguard Worker struct stat file_stats;
99*adcb0a62SAndroid Build Coastguard Worker if (fstat(fileno(f), &file_stats) == 0) {
100*adcb0a62SAndroid Build Coastguard Worker seekable_ = S_ISREG(file_stats.st_mode);
101*adcb0a62SAndroid Build Coastguard Worker }
102*adcb0a62SAndroid Build Coastguard Worker }
103*adcb0a62SAndroid Build Coastguard Worker
ZipWriter(ZipWriter && writer)104*adcb0a62SAndroid Build Coastguard Worker ZipWriter::ZipWriter(ZipWriter&& writer) noexcept
105*adcb0a62SAndroid Build Coastguard Worker : file_(writer.file_),
106*adcb0a62SAndroid Build Coastguard Worker seekable_(writer.seekable_),
107*adcb0a62SAndroid Build Coastguard Worker current_offset_(writer.current_offset_),
108*adcb0a62SAndroid Build Coastguard Worker state_(writer.state_),
109*adcb0a62SAndroid Build Coastguard Worker files_(std::move(writer.files_)),
110*adcb0a62SAndroid Build Coastguard Worker z_stream_(std::move(writer.z_stream_)),
111*adcb0a62SAndroid Build Coastguard Worker buffer_(std::move(writer.buffer_)) {
112*adcb0a62SAndroid Build Coastguard Worker writer.file_ = nullptr;
113*adcb0a62SAndroid Build Coastguard Worker writer.state_ = State::kError;
114*adcb0a62SAndroid Build Coastguard Worker }
115*adcb0a62SAndroid Build Coastguard Worker
operator =(ZipWriter && writer)116*adcb0a62SAndroid Build Coastguard Worker ZipWriter& ZipWriter::operator=(ZipWriter&& writer) noexcept {
117*adcb0a62SAndroid Build Coastguard Worker file_ = writer.file_;
118*adcb0a62SAndroid Build Coastguard Worker seekable_ = writer.seekable_;
119*adcb0a62SAndroid Build Coastguard Worker current_offset_ = writer.current_offset_;
120*adcb0a62SAndroid Build Coastguard Worker state_ = writer.state_;
121*adcb0a62SAndroid Build Coastguard Worker files_ = std::move(writer.files_);
122*adcb0a62SAndroid Build Coastguard Worker z_stream_ = std::move(writer.z_stream_);
123*adcb0a62SAndroid Build Coastguard Worker buffer_ = std::move(writer.buffer_);
124*adcb0a62SAndroid Build Coastguard Worker writer.file_ = nullptr;
125*adcb0a62SAndroid Build Coastguard Worker writer.state_ = State::kError;
126*adcb0a62SAndroid Build Coastguard Worker return *this;
127*adcb0a62SAndroid Build Coastguard Worker }
128*adcb0a62SAndroid Build Coastguard Worker
HandleError(int32_t error_code)129*adcb0a62SAndroid Build Coastguard Worker int32_t ZipWriter::HandleError(int32_t error_code) {
130*adcb0a62SAndroid Build Coastguard Worker state_ = State::kError;
131*adcb0a62SAndroid Build Coastguard Worker z_stream_.reset();
132*adcb0a62SAndroid Build Coastguard Worker return error_code;
133*adcb0a62SAndroid Build Coastguard Worker }
134*adcb0a62SAndroid Build Coastguard Worker
StartEntry(std::string_view path,size_t flags)135*adcb0a62SAndroid Build Coastguard Worker int32_t ZipWriter::StartEntry(std::string_view path, size_t flags) {
136*adcb0a62SAndroid Build Coastguard Worker uint32_t alignment = 0;
137*adcb0a62SAndroid Build Coastguard Worker if (flags & kAlign32) {
138*adcb0a62SAndroid Build Coastguard Worker flags &= ~kAlign32;
139*adcb0a62SAndroid Build Coastguard Worker alignment = 4;
140*adcb0a62SAndroid Build Coastguard Worker }
141*adcb0a62SAndroid Build Coastguard Worker return StartAlignedEntryWithTime(path, flags, time_t(), alignment);
142*adcb0a62SAndroid Build Coastguard Worker }
143*adcb0a62SAndroid Build Coastguard Worker
StartAlignedEntry(std::string_view path,size_t flags,uint32_t alignment)144*adcb0a62SAndroid Build Coastguard Worker int32_t ZipWriter::StartAlignedEntry(std::string_view path, size_t flags, uint32_t alignment) {
145*adcb0a62SAndroid Build Coastguard Worker return StartAlignedEntryWithTime(path, flags, time_t(), alignment);
146*adcb0a62SAndroid Build Coastguard Worker }
147*adcb0a62SAndroid Build Coastguard Worker
StartEntryWithTime(std::string_view path,size_t flags,time_t time)148*adcb0a62SAndroid Build Coastguard Worker int32_t ZipWriter::StartEntryWithTime(std::string_view path, size_t flags, time_t time) {
149*adcb0a62SAndroid Build Coastguard Worker uint32_t alignment = 0;
150*adcb0a62SAndroid Build Coastguard Worker if (flags & kAlign32) {
151*adcb0a62SAndroid Build Coastguard Worker flags &= ~kAlign32;
152*adcb0a62SAndroid Build Coastguard Worker alignment = 4;
153*adcb0a62SAndroid Build Coastguard Worker }
154*adcb0a62SAndroid Build Coastguard Worker return StartAlignedEntryWithTime(path, flags, time, alignment);
155*adcb0a62SAndroid Build Coastguard Worker }
156*adcb0a62SAndroid Build Coastguard Worker
ExtractTimeAndDate(time_t when,uint16_t * out_time,uint16_t * out_date)157*adcb0a62SAndroid Build Coastguard Worker static void ExtractTimeAndDate(time_t when, uint16_t* out_time, uint16_t* out_date) {
158*adcb0a62SAndroid Build Coastguard Worker /* round up to an even number of seconds */
159*adcb0a62SAndroid Build Coastguard Worker when = static_cast<time_t>((static_cast<unsigned long>(when) + 1) & (~1));
160*adcb0a62SAndroid Build Coastguard Worker
161*adcb0a62SAndroid Build Coastguard Worker struct tm tm_result;
162*adcb0a62SAndroid Build Coastguard Worker struct tm* ptm = localtime_r(&when, &tm_result);
163*adcb0a62SAndroid Build Coastguard Worker
164*adcb0a62SAndroid Build Coastguard Worker // The earliest valid time for ZIP file entries is 1980-01-01. See:
165*adcb0a62SAndroid Build Coastguard Worker // https://users.cs.jmu.edu/buchhofp/forensics/formats/pkzip.html.
166*adcb0a62SAndroid Build Coastguard Worker // Set any time before 1980 to 1980-01-01.
167*adcb0a62SAndroid Build Coastguard Worker if (ptm->tm_year < 80) {
168*adcb0a62SAndroid Build Coastguard Worker ptm->tm_year = 80;
169*adcb0a62SAndroid Build Coastguard Worker ptm->tm_mon = 0;
170*adcb0a62SAndroid Build Coastguard Worker ptm->tm_mday = 1;
171*adcb0a62SAndroid Build Coastguard Worker ptm->tm_hour = 0;
172*adcb0a62SAndroid Build Coastguard Worker ptm->tm_min = 0;
173*adcb0a62SAndroid Build Coastguard Worker ptm->tm_sec = 0;
174*adcb0a62SAndroid Build Coastguard Worker }
175*adcb0a62SAndroid Build Coastguard Worker
176*adcb0a62SAndroid Build Coastguard Worker *out_date =
177*adcb0a62SAndroid Build Coastguard Worker static_cast<uint16_t>((ptm->tm_year - 80) << 9 | (ptm->tm_mon + 1) << 5 | ptm->tm_mday);
178*adcb0a62SAndroid Build Coastguard Worker *out_time = static_cast<uint16_t>(ptm->tm_hour << 11 | ptm->tm_min << 5 | ptm->tm_sec >> 1);
179*adcb0a62SAndroid Build Coastguard Worker }
180*adcb0a62SAndroid Build Coastguard Worker
CopyFromFileEntry(const ZipWriter::FileEntry & src,bool use_data_descriptor,LocalFileHeader * dst)181*adcb0a62SAndroid Build Coastguard Worker static void CopyFromFileEntry(const ZipWriter::FileEntry& src, bool use_data_descriptor,
182*adcb0a62SAndroid Build Coastguard Worker LocalFileHeader* dst) {
183*adcb0a62SAndroid Build Coastguard Worker dst->lfh_signature = LocalFileHeader::kSignature;
184*adcb0a62SAndroid Build Coastguard Worker if (use_data_descriptor) {
185*adcb0a62SAndroid Build Coastguard Worker // Set this flag to denote that a DataDescriptor struct will appear after the data,
186*adcb0a62SAndroid Build Coastguard Worker // containing the crc and size fields.
187*adcb0a62SAndroid Build Coastguard Worker dst->gpb_flags |= kGPBDDFlagMask;
188*adcb0a62SAndroid Build Coastguard Worker
189*adcb0a62SAndroid Build Coastguard Worker // The size and crc fields must be 0.
190*adcb0a62SAndroid Build Coastguard Worker dst->compressed_size = 0u;
191*adcb0a62SAndroid Build Coastguard Worker dst->uncompressed_size = 0u;
192*adcb0a62SAndroid Build Coastguard Worker dst->crc32 = 0u;
193*adcb0a62SAndroid Build Coastguard Worker } else {
194*adcb0a62SAndroid Build Coastguard Worker dst->compressed_size = src.compressed_size;
195*adcb0a62SAndroid Build Coastguard Worker dst->uncompressed_size = src.uncompressed_size;
196*adcb0a62SAndroid Build Coastguard Worker dst->crc32 = src.crc32;
197*adcb0a62SAndroid Build Coastguard Worker }
198*adcb0a62SAndroid Build Coastguard Worker dst->compression_method = src.compression_method;
199*adcb0a62SAndroid Build Coastguard Worker dst->last_mod_time = src.last_mod_time;
200*adcb0a62SAndroid Build Coastguard Worker dst->last_mod_date = src.last_mod_date;
201*adcb0a62SAndroid Build Coastguard Worker DCHECK_LE(src.path.size(), std::numeric_limits<uint16_t>::max());
202*adcb0a62SAndroid Build Coastguard Worker dst->file_name_length = static_cast<uint16_t>(src.path.size());
203*adcb0a62SAndroid Build Coastguard Worker dst->extra_field_length = src.padding_length;
204*adcb0a62SAndroid Build Coastguard Worker }
205*adcb0a62SAndroid Build Coastguard Worker
StartAlignedEntryWithTime(std::string_view path,size_t flags,time_t time,uint32_t alignment)206*adcb0a62SAndroid Build Coastguard Worker int32_t ZipWriter::StartAlignedEntryWithTime(std::string_view path, size_t flags, time_t time,
207*adcb0a62SAndroid Build Coastguard Worker uint32_t alignment) {
208*adcb0a62SAndroid Build Coastguard Worker if (state_ != State::kWritingZip) {
209*adcb0a62SAndroid Build Coastguard Worker return kInvalidState;
210*adcb0a62SAndroid Build Coastguard Worker }
211*adcb0a62SAndroid Build Coastguard Worker
212*adcb0a62SAndroid Build Coastguard Worker // Can only have 16535 entries because of zip records.
213*adcb0a62SAndroid Build Coastguard Worker if (files_.size() == std::numeric_limits<uint16_t>::max()) {
214*adcb0a62SAndroid Build Coastguard Worker return HandleError(kIoError);
215*adcb0a62SAndroid Build Coastguard Worker }
216*adcb0a62SAndroid Build Coastguard Worker
217*adcb0a62SAndroid Build Coastguard Worker if (flags & kAlign32) {
218*adcb0a62SAndroid Build Coastguard Worker return kInvalidAlign32Flag;
219*adcb0a62SAndroid Build Coastguard Worker }
220*adcb0a62SAndroid Build Coastguard Worker
221*adcb0a62SAndroid Build Coastguard Worker if (powerof2(alignment) == 0) {
222*adcb0a62SAndroid Build Coastguard Worker return kInvalidAlignment;
223*adcb0a62SAndroid Build Coastguard Worker }
224*adcb0a62SAndroid Build Coastguard Worker if (alignment > std::numeric_limits<uint16_t>::max()) {
225*adcb0a62SAndroid Build Coastguard Worker return kInvalidAlignment;
226*adcb0a62SAndroid Build Coastguard Worker }
227*adcb0a62SAndroid Build Coastguard Worker
228*adcb0a62SAndroid Build Coastguard Worker FileEntry file_entry = {};
229*adcb0a62SAndroid Build Coastguard Worker file_entry.local_file_header_offset = current_offset_;
230*adcb0a62SAndroid Build Coastguard Worker file_entry.path = path;
231*adcb0a62SAndroid Build Coastguard Worker // No support for larger than 4GB files.
232*adcb0a62SAndroid Build Coastguard Worker if (file_entry.local_file_header_offset > std::numeric_limits<uint32_t>::max()) {
233*adcb0a62SAndroid Build Coastguard Worker return HandleError(kIoError);
234*adcb0a62SAndroid Build Coastguard Worker }
235*adcb0a62SAndroid Build Coastguard Worker
236*adcb0a62SAndroid Build Coastguard Worker if (!IsValidEntryName(reinterpret_cast<const uint8_t*>(file_entry.path.data()),
237*adcb0a62SAndroid Build Coastguard Worker file_entry.path.size())) {
238*adcb0a62SAndroid Build Coastguard Worker return kInvalidEntryName;
239*adcb0a62SAndroid Build Coastguard Worker }
240*adcb0a62SAndroid Build Coastguard Worker
241*adcb0a62SAndroid Build Coastguard Worker if (flags & ZipWriter::kCompress) {
242*adcb0a62SAndroid Build Coastguard Worker file_entry.compression_method = kCompressDeflated;
243*adcb0a62SAndroid Build Coastguard Worker
244*adcb0a62SAndroid Build Coastguard Worker int compression_level = (flags & ZipWriter::kDefaultCompression) ? 6 : 9;
245*adcb0a62SAndroid Build Coastguard Worker int32_t result = PrepareDeflate(compression_level);
246*adcb0a62SAndroid Build Coastguard Worker if (result != kNoError) {
247*adcb0a62SAndroid Build Coastguard Worker return result;
248*adcb0a62SAndroid Build Coastguard Worker }
249*adcb0a62SAndroid Build Coastguard Worker } else {
250*adcb0a62SAndroid Build Coastguard Worker file_entry.compression_method = kCompressStored;
251*adcb0a62SAndroid Build Coastguard Worker }
252*adcb0a62SAndroid Build Coastguard Worker
253*adcb0a62SAndroid Build Coastguard Worker ExtractTimeAndDate(time, &file_entry.last_mod_time, &file_entry.last_mod_date);
254*adcb0a62SAndroid Build Coastguard Worker
255*adcb0a62SAndroid Build Coastguard Worker off_t offset = current_offset_ + sizeof(LocalFileHeader) + file_entry.path.size();
256*adcb0a62SAndroid Build Coastguard Worker // prepare a pre-zeroed 4K memory block in case when we need to pad some aligned data.
257*adcb0a62SAndroid Build Coastguard Worker static constexpr char kSmallZeroPadding[4096] = {};
258*adcb0a62SAndroid Build Coastguard Worker // use this buffer if our preallocated one is too small
259*adcb0a62SAndroid Build Coastguard Worker std::vector<char> zero_padding_big;
260*adcb0a62SAndroid Build Coastguard Worker const char* zero_padding = nullptr;
261*adcb0a62SAndroid Build Coastguard Worker
262*adcb0a62SAndroid Build Coastguard Worker if (alignment != 0 && (offset & (alignment - 1))) {
263*adcb0a62SAndroid Build Coastguard Worker // Pad the extra field so the data will be aligned.
264*adcb0a62SAndroid Build Coastguard Worker uint16_t padding = static_cast<uint16_t>(alignment - (offset % alignment));
265*adcb0a62SAndroid Build Coastguard Worker file_entry.padding_length = padding;
266*adcb0a62SAndroid Build Coastguard Worker offset += padding;
267*adcb0a62SAndroid Build Coastguard Worker if (padding <= std::size(kSmallZeroPadding)) {
268*adcb0a62SAndroid Build Coastguard Worker zero_padding = kSmallZeroPadding;
269*adcb0a62SAndroid Build Coastguard Worker } else {
270*adcb0a62SAndroid Build Coastguard Worker zero_padding_big.resize(padding, 0);
271*adcb0a62SAndroid Build Coastguard Worker zero_padding = zero_padding_big.data();
272*adcb0a62SAndroid Build Coastguard Worker }
273*adcb0a62SAndroid Build Coastguard Worker }
274*adcb0a62SAndroid Build Coastguard Worker
275*adcb0a62SAndroid Build Coastguard Worker LocalFileHeader header = {};
276*adcb0a62SAndroid Build Coastguard Worker // Always start expecting a data descriptor. When the data has finished being written,
277*adcb0a62SAndroid Build Coastguard Worker // if it is possible to seek back, the GPB flag will reset and the sizes written.
278*adcb0a62SAndroid Build Coastguard Worker CopyFromFileEntry(file_entry, true /*use_data_descriptor*/, &header);
279*adcb0a62SAndroid Build Coastguard Worker
280*adcb0a62SAndroid Build Coastguard Worker if (fwrite(&header, sizeof(header), 1, file_) != 1) {
281*adcb0a62SAndroid Build Coastguard Worker return HandleError(kIoError);
282*adcb0a62SAndroid Build Coastguard Worker }
283*adcb0a62SAndroid Build Coastguard Worker
284*adcb0a62SAndroid Build Coastguard Worker if (fwrite(path.data(), 1, path.size(), file_) != path.size()) {
285*adcb0a62SAndroid Build Coastguard Worker return HandleError(kIoError);
286*adcb0a62SAndroid Build Coastguard Worker }
287*adcb0a62SAndroid Build Coastguard Worker
288*adcb0a62SAndroid Build Coastguard Worker if (file_entry.padding_length != 0 && fwrite(zero_padding, 1, file_entry.padding_length,
289*adcb0a62SAndroid Build Coastguard Worker file_) != file_entry.padding_length) {
290*adcb0a62SAndroid Build Coastguard Worker return HandleError(kIoError);
291*adcb0a62SAndroid Build Coastguard Worker }
292*adcb0a62SAndroid Build Coastguard Worker
293*adcb0a62SAndroid Build Coastguard Worker current_file_entry_ = std::move(file_entry);
294*adcb0a62SAndroid Build Coastguard Worker current_offset_ = offset;
295*adcb0a62SAndroid Build Coastguard Worker state_ = State::kWritingEntry;
296*adcb0a62SAndroid Build Coastguard Worker return kNoError;
297*adcb0a62SAndroid Build Coastguard Worker }
298*adcb0a62SAndroid Build Coastguard Worker
DiscardLastEntry()299*adcb0a62SAndroid Build Coastguard Worker int32_t ZipWriter::DiscardLastEntry() {
300*adcb0a62SAndroid Build Coastguard Worker if (state_ != State::kWritingZip || files_.empty()) {
301*adcb0a62SAndroid Build Coastguard Worker return kInvalidState;
302*adcb0a62SAndroid Build Coastguard Worker }
303*adcb0a62SAndroid Build Coastguard Worker
304*adcb0a62SAndroid Build Coastguard Worker FileEntry& last_entry = files_.back();
305*adcb0a62SAndroid Build Coastguard Worker current_offset_ = last_entry.local_file_header_offset;
306*adcb0a62SAndroid Build Coastguard Worker if (fseeko(file_, current_offset_, SEEK_SET) != 0) {
307*adcb0a62SAndroid Build Coastguard Worker return HandleError(kIoError);
308*adcb0a62SAndroid Build Coastguard Worker }
309*adcb0a62SAndroid Build Coastguard Worker files_.pop_back();
310*adcb0a62SAndroid Build Coastguard Worker return kNoError;
311*adcb0a62SAndroid Build Coastguard Worker }
312*adcb0a62SAndroid Build Coastguard Worker
GetLastEntry(FileEntry * out_entry)313*adcb0a62SAndroid Build Coastguard Worker int32_t ZipWriter::GetLastEntry(FileEntry* out_entry) {
314*adcb0a62SAndroid Build Coastguard Worker CHECK(out_entry != nullptr);
315*adcb0a62SAndroid Build Coastguard Worker
316*adcb0a62SAndroid Build Coastguard Worker if (files_.empty()) {
317*adcb0a62SAndroid Build Coastguard Worker return kInvalidState;
318*adcb0a62SAndroid Build Coastguard Worker }
319*adcb0a62SAndroid Build Coastguard Worker *out_entry = files_.back();
320*adcb0a62SAndroid Build Coastguard Worker return kNoError;
321*adcb0a62SAndroid Build Coastguard Worker }
322*adcb0a62SAndroid Build Coastguard Worker
PrepareDeflate(int compression_level)323*adcb0a62SAndroid Build Coastguard Worker int32_t ZipWriter::PrepareDeflate(int compression_level) {
324*adcb0a62SAndroid Build Coastguard Worker CHECK(state_ == State::kWritingZip);
325*adcb0a62SAndroid Build Coastguard Worker
326*adcb0a62SAndroid Build Coastguard Worker // Initialize the z_stream for compression.
327*adcb0a62SAndroid Build Coastguard Worker z_stream_ = std::unique_ptr<z_stream, void (*)(z_stream*)>(new z_stream(), DeleteZStream);
328*adcb0a62SAndroid Build Coastguard Worker
329*adcb0a62SAndroid Build Coastguard Worker #pragma GCC diagnostic push
330*adcb0a62SAndroid Build Coastguard Worker #pragma GCC diagnostic ignored "-Wold-style-cast"
331*adcb0a62SAndroid Build Coastguard Worker int zerr = deflateInit2(z_stream_.get(), compression_level, Z_DEFLATED,
332*adcb0a62SAndroid Build Coastguard Worker -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
333*adcb0a62SAndroid Build Coastguard Worker #pragma GCC diagnostic pop
334*adcb0a62SAndroid Build Coastguard Worker
335*adcb0a62SAndroid Build Coastguard Worker if (zerr != Z_OK) {
336*adcb0a62SAndroid Build Coastguard Worker if (zerr == Z_VERSION_ERROR) {
337*adcb0a62SAndroid Build Coastguard Worker LOG(ERROR) << "Installed zlib is not compatible with linked version (" << ZLIB_VERSION << ")";
338*adcb0a62SAndroid Build Coastguard Worker return HandleError(kZlibError);
339*adcb0a62SAndroid Build Coastguard Worker } else {
340*adcb0a62SAndroid Build Coastguard Worker LOG(ERROR) << "deflateInit2 failed (zerr=" << zerr << ")";
341*adcb0a62SAndroid Build Coastguard Worker return HandleError(kZlibError);
342*adcb0a62SAndroid Build Coastguard Worker }
343*adcb0a62SAndroid Build Coastguard Worker }
344*adcb0a62SAndroid Build Coastguard Worker
345*adcb0a62SAndroid Build Coastguard Worker z_stream_->next_out = buffer_.data();
346*adcb0a62SAndroid Build Coastguard Worker DCHECK_EQ(buffer_.size(), kBufSize);
347*adcb0a62SAndroid Build Coastguard Worker z_stream_->avail_out = static_cast<uint32_t>(buffer_.size());
348*adcb0a62SAndroid Build Coastguard Worker return kNoError;
349*adcb0a62SAndroid Build Coastguard Worker }
350*adcb0a62SAndroid Build Coastguard Worker
WriteBytes(const void * data,size_t len)351*adcb0a62SAndroid Build Coastguard Worker int32_t ZipWriter::WriteBytes(const void* data, size_t len) {
352*adcb0a62SAndroid Build Coastguard Worker if (state_ != State::kWritingEntry) {
353*adcb0a62SAndroid Build Coastguard Worker return HandleError(kInvalidState);
354*adcb0a62SAndroid Build Coastguard Worker }
355*adcb0a62SAndroid Build Coastguard Worker // Need to be able to mark down data correctly.
356*adcb0a62SAndroid Build Coastguard Worker if (len + static_cast<uint64_t>(current_file_entry_.uncompressed_size) >
357*adcb0a62SAndroid Build Coastguard Worker std::numeric_limits<uint32_t>::max()) {
358*adcb0a62SAndroid Build Coastguard Worker return HandleError(kIoError);
359*adcb0a62SAndroid Build Coastguard Worker }
360*adcb0a62SAndroid Build Coastguard Worker uint32_t len32 = static_cast<uint32_t>(len);
361*adcb0a62SAndroid Build Coastguard Worker
362*adcb0a62SAndroid Build Coastguard Worker int32_t result = kNoError;
363*adcb0a62SAndroid Build Coastguard Worker if (current_file_entry_.compression_method & kCompressDeflated) {
364*adcb0a62SAndroid Build Coastguard Worker result = CompressBytes(¤t_file_entry_, data, len32);
365*adcb0a62SAndroid Build Coastguard Worker } else {
366*adcb0a62SAndroid Build Coastguard Worker result = StoreBytes(¤t_file_entry_, data, len32);
367*adcb0a62SAndroid Build Coastguard Worker }
368*adcb0a62SAndroid Build Coastguard Worker
369*adcb0a62SAndroid Build Coastguard Worker if (result != kNoError) {
370*adcb0a62SAndroid Build Coastguard Worker return result;
371*adcb0a62SAndroid Build Coastguard Worker }
372*adcb0a62SAndroid Build Coastguard Worker
373*adcb0a62SAndroid Build Coastguard Worker current_file_entry_.crc32 = static_cast<uint32_t>(
374*adcb0a62SAndroid Build Coastguard Worker crc32(current_file_entry_.crc32, reinterpret_cast<const Bytef*>(data), len32));
375*adcb0a62SAndroid Build Coastguard Worker current_file_entry_.uncompressed_size += len32;
376*adcb0a62SAndroid Build Coastguard Worker return kNoError;
377*adcb0a62SAndroid Build Coastguard Worker }
378*adcb0a62SAndroid Build Coastguard Worker
StoreBytes(FileEntry * file,const void * data,uint32_t len)379*adcb0a62SAndroid Build Coastguard Worker int32_t ZipWriter::StoreBytes(FileEntry* file, const void* data, uint32_t len) {
380*adcb0a62SAndroid Build Coastguard Worker CHECK(state_ == State::kWritingEntry);
381*adcb0a62SAndroid Build Coastguard Worker
382*adcb0a62SAndroid Build Coastguard Worker if (fwrite(data, 1, len, file_) != len) {
383*adcb0a62SAndroid Build Coastguard Worker return HandleError(kIoError);
384*adcb0a62SAndroid Build Coastguard Worker }
385*adcb0a62SAndroid Build Coastguard Worker file->compressed_size += len;
386*adcb0a62SAndroid Build Coastguard Worker current_offset_ += len;
387*adcb0a62SAndroid Build Coastguard Worker return kNoError;
388*adcb0a62SAndroid Build Coastguard Worker }
389*adcb0a62SAndroid Build Coastguard Worker
CompressBytes(FileEntry * file,const void * data,uint32_t len)390*adcb0a62SAndroid Build Coastguard Worker int32_t ZipWriter::CompressBytes(FileEntry* file, const void* data, uint32_t len) {
391*adcb0a62SAndroid Build Coastguard Worker CHECK(state_ == State::kWritingEntry);
392*adcb0a62SAndroid Build Coastguard Worker CHECK(z_stream_);
393*adcb0a62SAndroid Build Coastguard Worker CHECK(z_stream_->next_out != nullptr);
394*adcb0a62SAndroid Build Coastguard Worker CHECK(z_stream_->avail_out != 0);
395*adcb0a62SAndroid Build Coastguard Worker
396*adcb0a62SAndroid Build Coastguard Worker // Prepare the input.
397*adcb0a62SAndroid Build Coastguard Worker z_stream_->next_in = reinterpret_cast<const uint8_t*>(data);
398*adcb0a62SAndroid Build Coastguard Worker z_stream_->avail_in = len;
399*adcb0a62SAndroid Build Coastguard Worker
400*adcb0a62SAndroid Build Coastguard Worker while (z_stream_->avail_in > 0) {
401*adcb0a62SAndroid Build Coastguard Worker // We have more data to compress.
402*adcb0a62SAndroid Build Coastguard Worker int zerr = deflate(z_stream_.get(), Z_NO_FLUSH);
403*adcb0a62SAndroid Build Coastguard Worker if (zerr != Z_OK) {
404*adcb0a62SAndroid Build Coastguard Worker return HandleError(kZlibError);
405*adcb0a62SAndroid Build Coastguard Worker }
406*adcb0a62SAndroid Build Coastguard Worker
407*adcb0a62SAndroid Build Coastguard Worker if (z_stream_->avail_out == 0) {
408*adcb0a62SAndroid Build Coastguard Worker // The output is full, let's write it to disk.
409*adcb0a62SAndroid Build Coastguard Worker size_t write_bytes = z_stream_->next_out - buffer_.data();
410*adcb0a62SAndroid Build Coastguard Worker if (fwrite(buffer_.data(), 1, write_bytes, file_) != write_bytes) {
411*adcb0a62SAndroid Build Coastguard Worker return HandleError(kIoError);
412*adcb0a62SAndroid Build Coastguard Worker }
413*adcb0a62SAndroid Build Coastguard Worker file->compressed_size += write_bytes;
414*adcb0a62SAndroid Build Coastguard Worker current_offset_ += write_bytes;
415*adcb0a62SAndroid Build Coastguard Worker
416*adcb0a62SAndroid Build Coastguard Worker // Reset the output buffer for the next input.
417*adcb0a62SAndroid Build Coastguard Worker z_stream_->next_out = buffer_.data();
418*adcb0a62SAndroid Build Coastguard Worker DCHECK_EQ(buffer_.size(), kBufSize);
419*adcb0a62SAndroid Build Coastguard Worker z_stream_->avail_out = static_cast<uint32_t>(buffer_.size());
420*adcb0a62SAndroid Build Coastguard Worker }
421*adcb0a62SAndroid Build Coastguard Worker }
422*adcb0a62SAndroid Build Coastguard Worker return kNoError;
423*adcb0a62SAndroid Build Coastguard Worker }
424*adcb0a62SAndroid Build Coastguard Worker
FlushCompressedBytes(FileEntry * file)425*adcb0a62SAndroid Build Coastguard Worker int32_t ZipWriter::FlushCompressedBytes(FileEntry* file) {
426*adcb0a62SAndroid Build Coastguard Worker CHECK(state_ == State::kWritingEntry);
427*adcb0a62SAndroid Build Coastguard Worker CHECK(z_stream_);
428*adcb0a62SAndroid Build Coastguard Worker CHECK(z_stream_->next_out != nullptr);
429*adcb0a62SAndroid Build Coastguard Worker CHECK(z_stream_->avail_out != 0);
430*adcb0a62SAndroid Build Coastguard Worker
431*adcb0a62SAndroid Build Coastguard Worker // Keep deflating while there isn't enough space in the buffer to
432*adcb0a62SAndroid Build Coastguard Worker // to complete the compress.
433*adcb0a62SAndroid Build Coastguard Worker int zerr;
434*adcb0a62SAndroid Build Coastguard Worker while ((zerr = deflate(z_stream_.get(), Z_FINISH)) == Z_OK) {
435*adcb0a62SAndroid Build Coastguard Worker CHECK(z_stream_->avail_out == 0);
436*adcb0a62SAndroid Build Coastguard Worker size_t write_bytes = z_stream_->next_out - buffer_.data();
437*adcb0a62SAndroid Build Coastguard Worker if (fwrite(buffer_.data(), 1, write_bytes, file_) != write_bytes) {
438*adcb0a62SAndroid Build Coastguard Worker return HandleError(kIoError);
439*adcb0a62SAndroid Build Coastguard Worker }
440*adcb0a62SAndroid Build Coastguard Worker file->compressed_size += write_bytes;
441*adcb0a62SAndroid Build Coastguard Worker current_offset_ += write_bytes;
442*adcb0a62SAndroid Build Coastguard Worker
443*adcb0a62SAndroid Build Coastguard Worker z_stream_->next_out = buffer_.data();
444*adcb0a62SAndroid Build Coastguard Worker DCHECK_EQ(buffer_.size(), kBufSize);
445*adcb0a62SAndroid Build Coastguard Worker z_stream_->avail_out = static_cast<uint32_t>(buffer_.size());
446*adcb0a62SAndroid Build Coastguard Worker }
447*adcb0a62SAndroid Build Coastguard Worker if (zerr != Z_STREAM_END) {
448*adcb0a62SAndroid Build Coastguard Worker return HandleError(kZlibError);
449*adcb0a62SAndroid Build Coastguard Worker }
450*adcb0a62SAndroid Build Coastguard Worker
451*adcb0a62SAndroid Build Coastguard Worker size_t write_bytes = z_stream_->next_out - buffer_.data();
452*adcb0a62SAndroid Build Coastguard Worker if (write_bytes != 0) {
453*adcb0a62SAndroid Build Coastguard Worker if (fwrite(buffer_.data(), 1, write_bytes, file_) != write_bytes) {
454*adcb0a62SAndroid Build Coastguard Worker return HandleError(kIoError);
455*adcb0a62SAndroid Build Coastguard Worker }
456*adcb0a62SAndroid Build Coastguard Worker file->compressed_size += write_bytes;
457*adcb0a62SAndroid Build Coastguard Worker current_offset_ += write_bytes;
458*adcb0a62SAndroid Build Coastguard Worker }
459*adcb0a62SAndroid Build Coastguard Worker z_stream_.reset();
460*adcb0a62SAndroid Build Coastguard Worker return kNoError;
461*adcb0a62SAndroid Build Coastguard Worker }
462*adcb0a62SAndroid Build Coastguard Worker
ShouldUseDataDescriptor() const463*adcb0a62SAndroid Build Coastguard Worker bool ZipWriter::ShouldUseDataDescriptor() const {
464*adcb0a62SAndroid Build Coastguard Worker // Only use a trailing "data descriptor" if the output isn't seekable.
465*adcb0a62SAndroid Build Coastguard Worker return !seekable_;
466*adcb0a62SAndroid Build Coastguard Worker }
467*adcb0a62SAndroid Build Coastguard Worker
FinishEntry()468*adcb0a62SAndroid Build Coastguard Worker int32_t ZipWriter::FinishEntry() {
469*adcb0a62SAndroid Build Coastguard Worker if (state_ != State::kWritingEntry) {
470*adcb0a62SAndroid Build Coastguard Worker return kInvalidState;
471*adcb0a62SAndroid Build Coastguard Worker }
472*adcb0a62SAndroid Build Coastguard Worker
473*adcb0a62SAndroid Build Coastguard Worker if (current_file_entry_.compression_method & kCompressDeflated) {
474*adcb0a62SAndroid Build Coastguard Worker int32_t result = FlushCompressedBytes(¤t_file_entry_);
475*adcb0a62SAndroid Build Coastguard Worker if (result != kNoError) {
476*adcb0a62SAndroid Build Coastguard Worker return result;
477*adcb0a62SAndroid Build Coastguard Worker }
478*adcb0a62SAndroid Build Coastguard Worker }
479*adcb0a62SAndroid Build Coastguard Worker
480*adcb0a62SAndroid Build Coastguard Worker if (ShouldUseDataDescriptor()) {
481*adcb0a62SAndroid Build Coastguard Worker // Some versions of ZIP don't allow STORED data to have a trailing DataDescriptor.
482*adcb0a62SAndroid Build Coastguard Worker // If this file is not seekable, or if the data is compressed, write a DataDescriptor.
483*adcb0a62SAndroid Build Coastguard Worker // We haven't supported zip64 format yet. Write both uncompressed size and compressed
484*adcb0a62SAndroid Build Coastguard Worker // size as uint32_t.
485*adcb0a62SAndroid Build Coastguard Worker std::vector<uint32_t> dataDescriptor = {
486*adcb0a62SAndroid Build Coastguard Worker DataDescriptor::kOptSignature, current_file_entry_.crc32,
487*adcb0a62SAndroid Build Coastguard Worker current_file_entry_.compressed_size, current_file_entry_.uncompressed_size};
488*adcb0a62SAndroid Build Coastguard Worker if (fwrite(dataDescriptor.data(), dataDescriptor.size() * sizeof(uint32_t), 1, file_) != 1) {
489*adcb0a62SAndroid Build Coastguard Worker return HandleError(kIoError);
490*adcb0a62SAndroid Build Coastguard Worker }
491*adcb0a62SAndroid Build Coastguard Worker
492*adcb0a62SAndroid Build Coastguard Worker current_offset_ += sizeof(uint32_t) * dataDescriptor.size();
493*adcb0a62SAndroid Build Coastguard Worker } else {
494*adcb0a62SAndroid Build Coastguard Worker // Seek back to the header and rewrite to include the size.
495*adcb0a62SAndroid Build Coastguard Worker if (fseeko(file_, current_file_entry_.local_file_header_offset, SEEK_SET) != 0) {
496*adcb0a62SAndroid Build Coastguard Worker return HandleError(kIoError);
497*adcb0a62SAndroid Build Coastguard Worker }
498*adcb0a62SAndroid Build Coastguard Worker
499*adcb0a62SAndroid Build Coastguard Worker LocalFileHeader header = {};
500*adcb0a62SAndroid Build Coastguard Worker CopyFromFileEntry(current_file_entry_, false /*use_data_descriptor*/, &header);
501*adcb0a62SAndroid Build Coastguard Worker
502*adcb0a62SAndroid Build Coastguard Worker if (fwrite(&header, sizeof(header), 1, file_) != 1) {
503*adcb0a62SAndroid Build Coastguard Worker return HandleError(kIoError);
504*adcb0a62SAndroid Build Coastguard Worker }
505*adcb0a62SAndroid Build Coastguard Worker
506*adcb0a62SAndroid Build Coastguard Worker if (fseeko(file_, current_offset_, SEEK_SET) != 0) {
507*adcb0a62SAndroid Build Coastguard Worker return HandleError(kIoError);
508*adcb0a62SAndroid Build Coastguard Worker }
509*adcb0a62SAndroid Build Coastguard Worker }
510*adcb0a62SAndroid Build Coastguard Worker
511*adcb0a62SAndroid Build Coastguard Worker files_.emplace_back(std::move(current_file_entry_));
512*adcb0a62SAndroid Build Coastguard Worker state_ = State::kWritingZip;
513*adcb0a62SAndroid Build Coastguard Worker return kNoError;
514*adcb0a62SAndroid Build Coastguard Worker }
515*adcb0a62SAndroid Build Coastguard Worker
Finish()516*adcb0a62SAndroid Build Coastguard Worker int32_t ZipWriter::Finish() {
517*adcb0a62SAndroid Build Coastguard Worker if (state_ != State::kWritingZip) {
518*adcb0a62SAndroid Build Coastguard Worker return kInvalidState;
519*adcb0a62SAndroid Build Coastguard Worker }
520*adcb0a62SAndroid Build Coastguard Worker
521*adcb0a62SAndroid Build Coastguard Worker off_t startOfCdr = current_offset_;
522*adcb0a62SAndroid Build Coastguard Worker for (FileEntry& file : files_) {
523*adcb0a62SAndroid Build Coastguard Worker CentralDirectoryRecord cdr = {};
524*adcb0a62SAndroid Build Coastguard Worker cdr.record_signature = CentralDirectoryRecord::kSignature;
525*adcb0a62SAndroid Build Coastguard Worker if (ShouldUseDataDescriptor()) {
526*adcb0a62SAndroid Build Coastguard Worker cdr.gpb_flags |= kGPBDDFlagMask;
527*adcb0a62SAndroid Build Coastguard Worker }
528*adcb0a62SAndroid Build Coastguard Worker cdr.compression_method = file.compression_method;
529*adcb0a62SAndroid Build Coastguard Worker cdr.last_mod_time = file.last_mod_time;
530*adcb0a62SAndroid Build Coastguard Worker cdr.last_mod_date = file.last_mod_date;
531*adcb0a62SAndroid Build Coastguard Worker cdr.crc32 = file.crc32;
532*adcb0a62SAndroid Build Coastguard Worker cdr.compressed_size = file.compressed_size;
533*adcb0a62SAndroid Build Coastguard Worker cdr.uncompressed_size = file.uncompressed_size;
534*adcb0a62SAndroid Build Coastguard Worker // Checked in IsValidEntryName.
535*adcb0a62SAndroid Build Coastguard Worker DCHECK_LE(file.path.size(), std::numeric_limits<uint16_t>::max());
536*adcb0a62SAndroid Build Coastguard Worker cdr.file_name_length = static_cast<uint16_t>(file.path.size());
537*adcb0a62SAndroid Build Coastguard Worker // Checked in StartAlignedEntryWithTime.
538*adcb0a62SAndroid Build Coastguard Worker DCHECK_LE(file.local_file_header_offset, std::numeric_limits<uint32_t>::max());
539*adcb0a62SAndroid Build Coastguard Worker cdr.local_file_header_offset = static_cast<uint32_t>(file.local_file_header_offset);
540*adcb0a62SAndroid Build Coastguard Worker if (fwrite(&cdr, sizeof(cdr), 1, file_) != 1) {
541*adcb0a62SAndroid Build Coastguard Worker return HandleError(kIoError);
542*adcb0a62SAndroid Build Coastguard Worker }
543*adcb0a62SAndroid Build Coastguard Worker
544*adcb0a62SAndroid Build Coastguard Worker if (fwrite(file.path.data(), 1, file.path.size(), file_) != file.path.size()) {
545*adcb0a62SAndroid Build Coastguard Worker return HandleError(kIoError);
546*adcb0a62SAndroid Build Coastguard Worker }
547*adcb0a62SAndroid Build Coastguard Worker
548*adcb0a62SAndroid Build Coastguard Worker current_offset_ += sizeof(cdr) + file.path.size();
549*adcb0a62SAndroid Build Coastguard Worker }
550*adcb0a62SAndroid Build Coastguard Worker
551*adcb0a62SAndroid Build Coastguard Worker EocdRecord er = {};
552*adcb0a62SAndroid Build Coastguard Worker er.eocd_signature = EocdRecord::kSignature;
553*adcb0a62SAndroid Build Coastguard Worker er.disk_num = 0;
554*adcb0a62SAndroid Build Coastguard Worker er.cd_start_disk = 0;
555*adcb0a62SAndroid Build Coastguard Worker // Checked when adding entries.
556*adcb0a62SAndroid Build Coastguard Worker DCHECK_LE(files_.size(), std::numeric_limits<uint16_t>::max());
557*adcb0a62SAndroid Build Coastguard Worker er.num_records_on_disk = static_cast<uint16_t>(files_.size());
558*adcb0a62SAndroid Build Coastguard Worker er.num_records = static_cast<uint16_t>(files_.size());
559*adcb0a62SAndroid Build Coastguard Worker if (current_offset_ > std::numeric_limits<uint32_t>::max()) {
560*adcb0a62SAndroid Build Coastguard Worker return HandleError(kIoError);
561*adcb0a62SAndroid Build Coastguard Worker }
562*adcb0a62SAndroid Build Coastguard Worker er.cd_size = static_cast<uint32_t>(current_offset_ - startOfCdr);
563*adcb0a62SAndroid Build Coastguard Worker er.cd_start_offset = static_cast<uint32_t>(startOfCdr);
564*adcb0a62SAndroid Build Coastguard Worker
565*adcb0a62SAndroid Build Coastguard Worker if (fwrite(&er, sizeof(er), 1, file_) != 1) {
566*adcb0a62SAndroid Build Coastguard Worker return HandleError(kIoError);
567*adcb0a62SAndroid Build Coastguard Worker }
568*adcb0a62SAndroid Build Coastguard Worker
569*adcb0a62SAndroid Build Coastguard Worker current_offset_ += sizeof(er);
570*adcb0a62SAndroid Build Coastguard Worker
571*adcb0a62SAndroid Build Coastguard Worker // Since we can BackUp() and potentially finish writing at an offset less than one we had
572*adcb0a62SAndroid Build Coastguard Worker // already written at, we must truncate the file.
573*adcb0a62SAndroid Build Coastguard Worker
574*adcb0a62SAndroid Build Coastguard Worker if (ftruncate(fileno(file_), current_offset_) != 0) {
575*adcb0a62SAndroid Build Coastguard Worker return HandleError(kIoError);
576*adcb0a62SAndroid Build Coastguard Worker }
577*adcb0a62SAndroid Build Coastguard Worker
578*adcb0a62SAndroid Build Coastguard Worker if (fflush(file_) != 0) {
579*adcb0a62SAndroid Build Coastguard Worker return HandleError(kIoError);
580*adcb0a62SAndroid Build Coastguard Worker }
581*adcb0a62SAndroid Build Coastguard Worker
582*adcb0a62SAndroid Build Coastguard Worker state_ = State::kDone;
583*adcb0a62SAndroid Build Coastguard Worker return kNoError;
584*adcb0a62SAndroid Build Coastguard Worker }
585