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

Side by Side Diff: chrome/common/zip.cc

Issue 8508003: zip: Add ZipReader and rework Unzip() using the new class. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fix a win failure Created 9 years, 1 month 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 | Annotate | Revision Log
« no previous file with comments | « chrome/chrome_tests.gypi ('k') | chrome/common/zip_reader.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium 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 "chrome/common/zip.h" 5 #include "chrome/common/zip.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/file_util.h" 8 #include "base/file_util.h"
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/string16.h" 10 #include "base/string16.h"
11 #include "base/string_util.h" 11 #include "base/string_util.h"
12 #include "chrome/common/zip_internal.h" 12 #include "chrome/common/zip_internal.h"
13 #include "chrome/common/zip_reader.h"
13 #include "net/base/file_stream.h" 14 #include "net/base/file_stream.h"
14 #include "third_party/zlib/contrib/minizip/unzip.h" 15 #include "third_party/zlib/contrib/minizip/unzip.h"
15 #include "third_party/zlib/contrib/minizip/zip.h" 16 #include "third_party/zlib/contrib/minizip/zip.h"
16 17
17 namespace { 18 namespace {
18 19
19 // Extract the 'current' selected file from the zip into dest_dir.
20 // Output filename is stored in out_file. Returns true on success.
21 bool ExtractCurrentFile(unzFile zip_file,
22 const FilePath& dest_dir) {
23 // We assume that the file names in zip files to be UTF-8. This is true
24 // for zip files created with Zip() and friends in the file.
25 char filename_in_zip_utf8[zip::internal::kZipMaxPath] = {0};
26 unz_file_info file_info;
27 int err = unzGetCurrentFileInfo(
28 zip_file, &file_info, filename_in_zip_utf8,
29 sizeof(filename_in_zip_utf8) - 1, NULL, 0, NULL, 0);
30 if (err != UNZ_OK)
31 return false;
32 if (filename_in_zip_utf8[0] == '\0')
33 return false;
34
35 err = unzOpenCurrentFile(zip_file);
36 if (err != UNZ_OK)
37 return false;
38
39 // Use of "Unsafe" function looks not good, but there is no safe way to
40 // do this on Linux anyway. See file_path.h for details.
41 FilePath file_path_in_zip = FilePath::FromUTF8Unsafe(filename_in_zip_utf8);
42
43 // Check the filename here for directory traversal issues. In the name of
44 // simplicity and security, we might reject a valid filename such as "a..b".
45 if (file_path_in_zip.value().find(FILE_PATH_LITERAL(".."))
46 != FilePath::StringType::npos)
47 return false;
48
49 FilePath dest_file = dest_dir.Append(file_path_in_zip);
50
51 // If this is a directory, just create it and return.
52 if (EndsWith(filename_in_zip_utf8, "/", false)) {
53 if (!file_util::CreateDirectory(dest_file))
54 return false;
55 return true;
56 }
57
58 // We can't rely on parent directory entries being specified in the zip, so we
59 // make sure they are created.
60 FilePath dir = dest_file.DirName();
61 if (!file_util::CreateDirectory(dir))
62 return false;
63
64 net::FileStream stream;
65 int flags = base::PLATFORM_FILE_CREATE_ALWAYS | base::PLATFORM_FILE_WRITE;
66 if (stream.Open(dest_file, flags) != 0)
67 return false;
68
69 bool ret = true;
70 int num_bytes = 0;
71 char buf[zip::internal::kZipBufSize];
72 do {
73 num_bytes = unzReadCurrentFile(zip_file, buf, zip::internal::kZipBufSize);
74 if (num_bytes < 0) {
75 // If num_bytes < 0, then it's a specific UNZ_* error code.
76 // While we're not currently handling these codes specifically, save
77 // it away in case we want to in the future.
78 err = num_bytes;
79 break;
80 }
81 if (num_bytes > 0) {
82 if (num_bytes != stream.Write(buf, num_bytes,
83 net::CompletionCallback())) {
84 ret = false;
85 break;
86 }
87 }
88 } while (num_bytes > 0);
89
90 stream.Close();
91 if (err == UNZ_OK)
92 err = unzCloseCurrentFile(zip_file);
93 else
94 unzCloseCurrentFile(zip_file); // Don't lose the original error code.
95 if (err != UNZ_OK)
96 ret = false;
97 return ret;
98 }
99
100 bool AddFileToZip(zipFile zip_file, const FilePath& src_dir) { 20 bool AddFileToZip(zipFile zip_file, const FilePath& src_dir) {
101 net::FileStream stream; 21 net::FileStream stream;
102 int flags = base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ; 22 int flags = base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ;
103 if (stream.Open(src_dir, flags) != 0) { 23 if (stream.Open(src_dir, flags) != 0) {
104 DLOG(ERROR) << "Could not open stream for path " 24 DLOG(ERROR) << "Could not open stream for path "
105 << src_dir.value(); 25 << src_dir.value();
106 return false; 26 return false;
107 } 27 }
108 28
109 int num_bytes; 29 int num_bytes;
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
163 83
164 bool ExcludeHiddenFilesFilter(const FilePath& file_path) { 84 bool ExcludeHiddenFilesFilter(const FilePath& file_path) {
165 return file_path.BaseName().value()[0] != '.'; 85 return file_path.BaseName().value()[0] != '.';
166 } 86 }
167 87
168 } // namespace 88 } // namespace
169 89
170 namespace zip { 90 namespace zip {
171 91
172 bool Unzip(const FilePath& src_file, const FilePath& dest_dir) { 92 bool Unzip(const FilePath& src_file, const FilePath& dest_dir) {
173 unzFile zip_file = internal::OpenForUnzipping(src_file.AsUTF8Unsafe()); 93 ZipReader reader;
174 if (!zip_file) { 94 if (!reader.Open(src_file)) {
175 DLOG(WARNING) << "couldn't create file " << src_file.value(); 95 DLOG(WARNING) << "Failed to open " << src_file.value();
176 return false; 96 return false;
177 } 97 }
178 unz_global_info zip_info; 98 while (reader.HasMore()) {
179 int err; 99 if (!reader.OpenCurrentEntryInZip()) {
180 err = unzGetGlobalInfo(zip_file, &zip_info); 100 DLOG(WARNING) << "Failed to open the current file in zip";
181 if (err != UNZ_OK) { 101 return false;
182 DLOG(WARNING) << "couldn't open zip " << src_file.value();
183 return false;
184 }
185 bool ret = true;
186 for (unsigned int i = 0; i < zip_info.number_entry; ++i) {
187 if (!ExtractCurrentFile(zip_file, dest_dir)) {
188 ret = false;
189 break;
190 } 102 }
191 103 if (reader.current_entry_info()->is_unsafe()) {
192 if (i + 1 < zip_info.number_entry) { 104 DLOG(WARNING) << "Found an unsafe file in zip "
193 err = unzGoToNextFile(zip_file); 105 << reader.current_entry_info()->file_path().value();
194 if (err != UNZ_OK) { 106 return false;
195 DLOG(WARNING) << "error %d in unzGoToNextFile"; 107 }
196 ret = false; 108 if (!reader.ExtractCurrentEntryIntoDirectory(dest_dir)) {
197 break; 109 DLOG(WARNING) << "Failed to extract "
198 } 110 << reader.current_entry_info()->file_path().value();
111 return false;
112 }
113 if (!reader.AdvanceToNextEntry()) {
114 DLOG(WARNING) << "Failed to advance to the next file";
115 return false;
199 } 116 }
200 } 117 }
201 unzClose(zip_file); 118 return true;
202 return ret;
203 } 119 }
204 120
205 bool ZipWithFilterCallback(const FilePath& src_dir, const FilePath& dest_file, 121 bool ZipWithFilterCallback(const FilePath& src_dir, const FilePath& dest_file,
206 const FilterCallback& filter_cb) { 122 const FilterCallback& filter_cb) {
207 DCHECK(file_util::DirectoryExists(src_dir)); 123 DCHECK(file_util::DirectoryExists(src_dir));
208 124
209 zipFile zip_file = internal::OpenForZipping(dest_file.AsUTF8Unsafe(), 125 zipFile zip_file = internal::OpenForZipping(dest_file.AsUTF8Unsafe(),
210 APPEND_STATUS_CREATE); 126 APPEND_STATUS_CREATE);
211 127
212 if (!zip_file) { 128 if (!zip_file) {
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
245 if (include_hidden_files) { 161 if (include_hidden_files) {
246 return ZipWithFilterCallback( 162 return ZipWithFilterCallback(
247 src_dir, dest_file, base::Bind(&ExcludeNoFilesFilter)); 163 src_dir, dest_file, base::Bind(&ExcludeNoFilesFilter));
248 } else { 164 } else {
249 return ZipWithFilterCallback( 165 return ZipWithFilterCallback(
250 src_dir, dest_file, base::Bind(&ExcludeHiddenFilesFilter)); 166 src_dir, dest_file, base::Bind(&ExcludeHiddenFilesFilter));
251 } 167 }
252 } 168 }
253 169
254 } // namespace zip 170 } // namespace zip
OLDNEW
« no previous file with comments | « chrome/chrome_tests.gypi ('k') | chrome/common/zip_reader.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698