Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(242)

Side by Side Diff: ui/file_manager/zip_archiver/cpp/compressor_archive_libarchive.cc

Issue 2807063002: Replace Libarchive with MiniZip. (Closed)
Patch Set: Delete BUILD.gn Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2017 The Chromium OS Authors. All rights reserved. 1 // Copyright 2017 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "compressor_archive_libarchive.h" 5 #include "compressor_archive_libarchive.h"
6 6
7 #include <cerrno> 7 #include <cerrno>
8 #include <cstring> 8 #include <cstring>
9 9
10 #include "archive_entry.h" 10 #include "base/time/time.h"
11 #include "ppapi/cpp/logging.h" 11 #include "ppapi/cpp/logging.h"
12 12
13 namespace { 13 namespace compressor_archive_functions {
14 // Nothing to do here because JavaScript takes care of file open operations. 14 // Called when minizip tries to open a zip archive file. We do nothing here
mtomasz 2017/04/10 07:15:08 nit: Let's add \n after the namespace line for bet
takise 2017/04/11 06:00:51 Done.
15 int CustomArchiveOpen(archive* archive_object, void* client_data) { 15 // because JavaScript takes care of file opening operation.
16 return ARCHIVE_OK; 16 void* CustomArchiveOpen(void* opaque, const char* filename, int mode) {
17 } 17 return opaque;
18 18 }
19 // Called when any data chunk must be written on the archive. It copies data 19
20 // from the given buffer processed by libarchive to an array buffer and passes 20 // This function is not called because we don't unpack zip files here.
21 // it to compressor_stream. 21 uLong CustomArchiveRead(void* opaque, void* /*stream*/, void* buf, uLong size) {
mtomasz 2017/04/10 07:15:08 nit: We usually comment out unused arguments. So l
takise 2017/04/11 06:00:51 Done.
22 ssize_t CustomArchiveWrite(archive* archive_object, void* client_data, 22 return 0 /* Success */;
23 const void* buffer, size_t length) { 23 }
24 CompressorArchiveLibarchive* compressor_libarchive = 24
25 static_cast<CompressorArchiveLibarchive*>(client_data); 25 // Called when data chunk must be written on the archive. It copies data
26 26 // from the given buffer processed by minizip to an array buffer and passes
27 const char* char_buffer = static_cast<const char*>(buffer); 27 // it to compressor_stream.
28 28 uLong CustomArchiveWrite(void* opaque,
mtomasz 2017/04/10 07:15:08 Why is this argument called opaque? Can we rename
takise 2017/04/11 06:00:51 Done.
29 // Copy the data in buffer to array_buffer. 29 void* /*stream*/,
30 PP_DCHECK(length > 0); 30 const void* zip_buffer,
31 pp::VarArrayBuffer array_buffer(length); 31 uLong zip_length) {
32 char* array_buffer_data = static_cast<char*>(array_buffer.Map()); 32 CompressorArchiveLibarchive* compressor_libarchive =
33 memcpy(array_buffer_data, char_buffer, length); 33 static_cast<CompressorArchiveLibarchive*>(opaque);
34 array_buffer.Unmap(); 34
35 35 int64_t written_bytes = compressor_libarchive->compressor_stream()->Write(
36 ssize_t written_bytes = 36 compressor_libarchive->offset_, zip_length, zip_buffer);
37 compressor_libarchive->compressor_stream()->Write(length, array_buffer); 37
38 38 if (written_bytes != zip_length)
39 // Negative written_bytes represents an error. 39 return 0 /* Error */;
40 if (written_bytes < 0) { 40
41 // When writing fails, archive_set_error() should be called and -1 should 41 // Update offset_ and length_.
42 // be returned. 42 compressor_libarchive->offset_ += written_bytes;
43 archive_set_error( 43 if (compressor_libarchive->offset_ > compressor_libarchive->length_)
44 compressor_libarchive->archive(), EIO, "Failed to write a chunk."); 44 compressor_libarchive->length_ = compressor_libarchive->offset_;
45 return -1; 45 return static_cast<uLong>(written_bytes);
46 } 46 }
47 return written_bytes; 47
48 } 48 // Returns the offset from the beginning of the data.
49 49 long CustomArchiveTell(void* opaque, void* /*stream*/) {
50 // Nothing to do here because JavaScript takes care of file close operations. 50 CompressorArchiveLibarchive* compressor_libarchive =
mtomasz 2017/04/10 07:15:08 Can we rename libarchive from variable/class/metho
51 int CustomArchiveClose(archive* archive_object, void* client_data) { 51 static_cast<CompressorArchiveLibarchive*>(opaque);
52 return ARCHIVE_OK; 52 return static_cast<long>(compressor_libarchive->offset_);
53 } 53 }
54 } 54
55 // Moves the current offset to the specified position.
56 long CustomArchiveSeek(void* opaque,
57 void* /*stream*/,
58 uLong offset,
59 int origin) {
60 CompressorArchiveLibarchive* compressor_libarchive =
61 static_cast<CompressorArchiveLibarchive*>(opaque);
62
63 if (origin == ZLIB_FILEFUNC_SEEK_CUR) {
64 compressor_libarchive->offset_ =
65 std::min(compressor_libarchive->offset_ + static_cast<int64_t>(offset),
66 compressor_libarchive->length_);
67 return 0 /* Success */;
68 }
69 if (origin == ZLIB_FILEFUNC_SEEK_END) {
70 compressor_libarchive->offset_ =
71 std::max(compressor_libarchive->length_ - static_cast<int64_t>(offset),
72 0);
73 return 0 /* Success */;
74 }
75 if (origin == ZLIB_FILEFUNC_SEEK_SET) {
76 compressor_libarchive->offset_ =
77 std::min(static_cast<int64_t>(offset), compressor_libarchive->length_);
78 return 0 /* Success */;
79 }
80 return -1 /* Error */;
81 }
82
83 // Releases all used resources. opaque points to compressor_libarchive and
84 // it is deleted elsewhere, so we don't need to delete it here.
mtomasz 2017/04/10 07:15:08 nit: elsewhere -> ... Can we write a method name i
takise 2017/04/11 06:00:51 Done.
85 int CustomArchiveClose(void* opaque, void* /*stream*/) {
86 return 0 /* Success */;
87 }
88
89 // Returns the last error that happened when writing data. This function always
90 // returns zero, which means there are no errors.
91 int CustomArchiveError(void* /*opaque*/, void* /*stream*/) {
92 return 0 /* Success */;
93 }
94
95 } // compressor_archive_functions
55 96
56 CompressorArchiveLibarchive::CompressorArchiveLibarchive( 97 CompressorArchiveLibarchive::CompressorArchiveLibarchive(
57 CompressorStream* compressor_stream) 98 CompressorStream* compressor_stream)
58 : CompressorArchive(compressor_stream), 99 : CompressorArchive(compressor_stream),
59 compressor_stream_(compressor_stream) { 100 compressor_stream_(compressor_stream),
101 zip_file_(NULL),
102 offset_(0),
103 length_(0) {
60 destination_buffer_ = 104 destination_buffer_ =
61 new char[compressor_archive_constants::kMaximumDataChunkSize]; 105 new char[compressor_stream_constants::kMaximumDataChunkSize];
62 } 106 }
63 107
64 CompressorArchiveLibarchive::~CompressorArchiveLibarchive() { 108 CompressorArchiveLibarchive::~CompressorArchiveLibarchive() {
65 delete destination_buffer_; 109 delete destination_buffer_;
66 } 110 }
67 111
68 void CompressorArchiveLibarchive::CreateArchive() { 112 bool CompressorArchiveLibarchive::CreateArchive() {
69 archive_ = archive_write_new(); 113 // Set up archive object.
70 archive_write_set_format_zip(archive_); 114 zlib_filefunc_def zip_funcs;
71 115 zip_funcs.zopen_file = compressor_archive_functions::CustomArchiveOpen;
72 // Passing 1 as the second argument causes the final chunk not to be padded. 116 zip_funcs.zread_file = compressor_archive_functions::CustomArchiveRead;
73 archive_write_set_bytes_in_last_block(archive_, 1); 117 zip_funcs.zwrite_file = compressor_archive_functions::CustomArchiveWrite;
74 archive_write_set_bytes_per_block( 118 zip_funcs.ztell_file = compressor_archive_functions::CustomArchiveTell;
75 archive_, compressor_archive_constants::kMaximumDataChunkSize); 119 zip_funcs.zseek_file = compressor_archive_functions::CustomArchiveSeek;
76 archive_write_open(archive_, this, CustomArchiveOpen, 120 zip_funcs.zclose_file = compressor_archive_functions::CustomArchiveClose;
77 CustomArchiveWrite, CustomArchiveClose); 121 zip_funcs.zerror_file = compressor_archive_functions::CustomArchiveError;
78 } 122 zip_funcs.opaque = this;
79 123
80 void CompressorArchiveLibarchive::AddToArchive( 124 zip_file_ = zipOpen2(NULL /* pathname */,
mtomasz 2017/04/10 07:15:08 NULL -> nullptr here and in other places
takise 2017/04/11 06:00:51 Done.
81 const std::string& filename, 125 APPEND_STATUS_CREATE,
82 int64_t file_size, 126 NULL /* globalcomment */,
83 time_t modification_time, 127 &zip_funcs);
84 bool is_directory) { 128 if (!zip_file_) {
85 entry = archive_entry_new(); 129 set_error_message(compressor_archive_constants::kCreateArchiveError);
86 130 return false /* Error */;
87 archive_entry_set_pathname(entry, filename.c_str()); 131 }
88 archive_entry_set_size(entry, file_size); 132 return true /* Success */;
89 archive_entry_set_mtime(entry, modification_time, 0 /* millisecond */); 133 }
90 134
91 if (is_directory) { 135 bool CompressorArchiveLibarchive::AddToArchive(const std::string& _filename,
mtomasz 2017/04/10 07:15:08 nit: We never prefix with _. Can we keep filename
takise 2017/04/11 06:00:51 Done.
92 archive_entry_set_filetype(entry, AE_IFDIR); 136 int64_t file_size,
93 archive_entry_set_perm( 137 int64_t modification_time,
94 entry, compressor_archive_constants::kDirectoryPermission); 138 bool is_directory) {
95 } else { 139 // Minizip takes filenames that end with '/' as directories.
96 archive_entry_set_filetype(entry, AE_IFREG); 140 std::string filename = _filename;
97 archive_entry_set_perm( 141 if (is_directory)
98 entry, compressor_archive_constants::kFilePermission); 142 filename += "/";
mtomasz 2017/04/10 07:15:08 Does it work with Windows paths? If not, did it wo
99 } 143
100 archive_write_header(archive_, entry); 144 // Fill zipfileMetadata with modification_time.
101 // If archive_errno() returns 0, the header was written correctly. 145 zip_fileinfo zipfileMetadata;
102 if (archive_errno(archive_) != 0) { 146 // modification_time is millisecond-based, while FromTimeT takes seconds.
103 CloseArchive(true /* hasError */); 147 base::Time tm = base::Time::FromTimeT((int64_t)modification_time / 1000);
104 return; 148 base::Time::Exploded exploded_time = {};
105 } 149 tm.LocalExplode(&exploded_time);
106 150 zipfileMetadata.tmz_date.tm_sec = exploded_time.second;
151 zipfileMetadata.tmz_date.tm_min = exploded_time.minute;
152 zipfileMetadata.tmz_date.tm_hour = exploded_time.hour;
153 zipfileMetadata.tmz_date.tm_year = exploded_time.year;
154 zipfileMetadata.tmz_date.tm_mday = exploded_time.day_of_month;
155 // Convert from 1-based to 0-based.
156 zipfileMetadata.tmz_date.tm_mon = exploded_time.month - 1;
157
158 // Section 4.4.4 http://www.pkware.com/documents/casestudies/APPNOTE.TXT
159 // Setting the Language encoding flag so the file is told to be in utf-8.
160 const uLong LANGUAGE_ENCODING_FLAG = 0x1 << 11;
161
162 int open_result = zipOpenNewFileInZip4(zip_file_, // file
163 filename.c_str(), // filename
164 &zipfileMetadata, // zipfi
165 NULL, // extrafield_local
166 0u, // size_extrafield_local
167 NULL, // extrafield_global
168 0u, // size_extrafield_global
169 NULL, // comment
170 Z_DEFLATED, // method
171 Z_DEFAULT_COMPRESSION, // level
172 0, // raw
173 -MAX_WBITS, // windowBits
174 DEF_MEM_LEVEL, // memLevel
175 Z_DEFAULT_STRATEGY, // strategy
176 NULL, // password
177 0, // crcForCrypting
178 0, // versionMadeBy
179 LANGUAGE_ENCODING_FLAG); // flagBase
180 if (open_result != ZIP_OK) {
181 CloseArchive(true /* has_error */);
182 set_error_message(compressor_archive_constants::kAddtoArchiveError);
183 return false /* Error */;
184 }
185
186 bool has_error = false;
107 if (!is_directory) { 187 if (!is_directory) {
108 int64_t remaining_size = file_size; 188 int64_t remaining_size = file_size;
109 while (remaining_size > 0) { 189 while (remaining_size > 0) {
110 int64_t chunk_size = std::min(remaining_size, 190 int64_t chunk_size = std::min(remaining_size,
111 compressor_archive_constants::kMaximumDataChunkSize); 191 compressor_stream_constants::kMaximumDataChunkSize);
112 PP_DCHECK(chunk_size > 0); 192 PP_DCHECK(chunk_size > 0);
113 193
114 int64_t read_bytes = 194 int64_t read_bytes =
115 compressor_stream_->Read(chunk_size, destination_buffer_); 195 compressor_stream_->Read(chunk_size, destination_buffer_);
196
116 // Negative read_bytes indicates an error occurred when reading chunks. 197 // Negative read_bytes indicates an error occurred when reading chunks.
117 if (read_bytes < 0) { 198 // 0 just means there is no more data available, but here we need positive
118 CloseArchive(true /* hasError */); 199 // length of bytes, so this is also an error here.
200 if (read_bytes <= 0) {
201 has_error = true;
119 break; 202 break;
120 } 203 }
121 204
122 int64_t written_bytes = 205 if (zipWriteInFileInZip(zip_file_, destination_buffer_, read_bytes) !=
123 archive_write_data(archive_, destination_buffer_, read_bytes); 206 ZIP_OK) {
124 // If archive_errno() returns 0, the buffer was written correctly. 207 has_error = true;
125 if (archive_errno(archive_) != 0) {
126 CloseArchive(true /* hasError */);
127 break; 208 break;
128 } 209 }
129 PP_DCHECK(written_bytes > 0); 210 remaining_size -= read_bytes;
130
131 remaining_size -= written_bytes;
132 } 211 }
133 } 212 }
134 213
135 archive_entry_free(entry); 214 if (!has_error && zipCloseFileInZip(zip_file_) != ZIP_OK)
136 } 215 has_error = true;
137 216
138 void CompressorArchiveLibarchive::CloseArchive(bool has_error) { 217 if (has_error) {
139 // If has_error is true, mark the archive object as being unusable and 218 CloseArchive(true /* has_error */);
140 // release resources without writing no more data on the archive. 219 set_error_message(compressor_archive_constants::kAddtoArchiveError);
141 if (has_error) 220 return false /* Error */;
142 archive_write_fail(archive_); 221 }
143 if (archive_) { 222
144 archive_write_free(archive_); 223 return true /* Success */;
145 archive_ = NULL; 224 }
146 } 225
147 } 226 bool CompressorArchiveLibarchive::CloseArchive(bool has_error) {
227 if (zipClose(zip_file_, NULL /* global_comment */) != ZIP_OK) {
228 set_error_message(compressor_archive_constants::kCloseArchiveError);
229 return false /* Error */;
230 }
231 if (!has_error) {
232 if (compressor_stream()->Flush() < 0) {
233 set_error_message(compressor_archive_constants::kCloseArchiveError);
234 return false /* Error */;
235 }
236 }
237 return true /* Success */;
238 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698