| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "chrome/test/chromedriver/zip.h" | |
| 6 | |
| 7 #include "base/bind.h" | |
| 8 #include "base/file_util.h" | |
| 9 #include "base/logging.h" | |
| 10 #include "base/string16.h" | |
| 11 #include "base/string_util.h" | |
| 12 #include "chrome/test/chromedriver/zip_internal.h" | |
| 13 #include "chrome/test/chromedriver/zip_reader.h" | |
| 14 #include "net/base/file_stream.h" | |
| 15 | |
| 16 #if defined(USE_SYSTEM_MINIZIP) | |
| 17 #include <minizip/unzip.h> | |
| 18 #include <minizip/zip.h> | |
| 19 #else | |
| 20 #include "third_party/zlib/contrib/minizip/unzip.h" | |
| 21 #include "third_party/zlib/contrib/minizip/zip.h" | |
| 22 #endif | |
| 23 | |
| 24 namespace { | |
| 25 | |
| 26 bool AddFileToZip(zipFile zip_file, const base::FilePath& src_dir) { | |
| 27 net::FileStream stream(NULL); | |
| 28 int flags = base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ; | |
| 29 if (stream.OpenSync(src_dir, flags) != 0) { | |
| 30 DLOG(ERROR) << "Could not open stream for path " | |
| 31 << src_dir.value(); | |
| 32 return false; | |
| 33 } | |
| 34 | |
| 35 int num_bytes; | |
| 36 char buf[zip::internal::kZipBufSize]; | |
| 37 do { | |
| 38 num_bytes = stream.ReadSync(buf, zip::internal::kZipBufSize); | |
| 39 if (num_bytes > 0) { | |
| 40 if (ZIP_OK != zipWriteInFileInZip(zip_file, buf, num_bytes)) { | |
| 41 DLOG(ERROR) << "Could not write data to zip for path " | |
| 42 << src_dir.value(); | |
| 43 return false; | |
| 44 } | |
| 45 } | |
| 46 } while (num_bytes > 0); | |
| 47 | |
| 48 return true; | |
| 49 } | |
| 50 | |
| 51 bool AddEntryToZip(zipFile zip_file, const base::FilePath& path, | |
| 52 const base::FilePath& root_path) { | |
| 53 std::string str_path = | |
| 54 path.AsUTF8Unsafe().substr(root_path.value().length() + 1); | |
| 55 #if defined(OS_WIN) | |
| 56 ReplaceSubstringsAfterOffset(&str_path, 0u, "\\", "/"); | |
| 57 #endif | |
| 58 | |
| 59 bool is_directory = file_util::DirectoryExists(path); | |
| 60 if (is_directory) | |
| 61 str_path += "/"; | |
| 62 | |
| 63 if (ZIP_OK != zipOpenNewFileInZip( | |
| 64 zip_file, str_path.c_str(), | |
| 65 NULL, NULL, 0u, NULL, 0u, NULL, // file info, extrafield local, length, | |
| 66 // extrafield global, length, comment | |
| 67 Z_DEFLATED, Z_DEFAULT_COMPRESSION)) { | |
| 68 DLOG(ERROR) << "Could not open zip file entry " << str_path; | |
| 69 return false; | |
| 70 } | |
| 71 | |
| 72 bool success = true; | |
| 73 if (!is_directory) { | |
| 74 success = AddFileToZip(zip_file, path); | |
| 75 } | |
| 76 | |
| 77 if (ZIP_OK != zipCloseFileInZip(zip_file)) { | |
| 78 DLOG(ERROR) << "Could not close zip file entry " << str_path; | |
| 79 return false; | |
| 80 } | |
| 81 | |
| 82 return success; | |
| 83 } | |
| 84 | |
| 85 bool ExcludeNoFilesFilter(const base::FilePath& file_path) { | |
| 86 return true; | |
| 87 } | |
| 88 | |
| 89 bool ExcludeHiddenFilesFilter(const base::FilePath& file_path) { | |
| 90 return file_path.BaseName().value()[0] != '.'; | |
| 91 } | |
| 92 | |
| 93 } // namespace | |
| 94 | |
| 95 namespace zip { | |
| 96 | |
| 97 bool Unzip(const base::FilePath& src_file, const base::FilePath& dest_dir) { | |
| 98 ZipReader reader; | |
| 99 if (!reader.Open(src_file)) { | |
| 100 DLOG(WARNING) << "Failed to open " << src_file.value(); | |
| 101 return false; | |
| 102 } | |
| 103 while (reader.HasMore()) { | |
| 104 if (!reader.OpenCurrentEntryInZip()) { | |
| 105 DLOG(WARNING) << "Failed to open the current file in zip"; | |
| 106 return false; | |
| 107 } | |
| 108 if (reader.current_entry_info()->is_unsafe()) { | |
| 109 DLOG(WARNING) << "Found an unsafe file in zip " | |
| 110 << reader.current_entry_info()->file_path().value(); | |
| 111 return false; | |
| 112 } | |
| 113 if (!reader.ExtractCurrentEntryIntoDirectory(dest_dir)) { | |
| 114 DLOG(WARNING) << "Failed to extract " | |
| 115 << reader.current_entry_info()->file_path().value(); | |
| 116 return false; | |
| 117 } | |
| 118 if (!reader.AdvanceToNextEntry()) { | |
| 119 DLOG(WARNING) << "Failed to advance to the next file"; | |
| 120 return false; | |
| 121 } | |
| 122 } | |
| 123 return true; | |
| 124 } | |
| 125 | |
| 126 bool ZipWithFilterCallback(const base::FilePath& src_dir, | |
| 127 const base::FilePath& dest_file, | |
| 128 const FilterCallback& filter_cb) { | |
| 129 DCHECK(file_util::DirectoryExists(src_dir)); | |
| 130 | |
| 131 zipFile zip_file = internal::OpenForZipping(dest_file.AsUTF8Unsafe(), | |
| 132 APPEND_STATUS_CREATE); | |
| 133 | |
| 134 if (!zip_file) { | |
| 135 DLOG(WARNING) << "couldn't create file " << dest_file.value(); | |
| 136 return false; | |
| 137 } | |
| 138 | |
| 139 bool success = true; | |
| 140 file_util::FileEnumerator file_enumerator(src_dir, true /* recursive */, | |
| 141 file_util::FileEnumerator::FILES | | |
| 142 file_util::FileEnumerator::DIRECTORIES); | |
| 143 for (base::FilePath path = file_enumerator.Next(); !path.value().empty(); | |
| 144 path = file_enumerator.Next()) { | |
| 145 if (!filter_cb.Run(path)) { | |
| 146 continue; | |
| 147 } | |
| 148 | |
| 149 if (!AddEntryToZip(zip_file, path, src_dir)) { | |
| 150 success = false; | |
| 151 return false; | |
| 152 } | |
| 153 } | |
| 154 | |
| 155 if (ZIP_OK != zipClose(zip_file, NULL)) { | |
| 156 DLOG(ERROR) << "Error closing zip file " << dest_file.value(); | |
| 157 return false; | |
| 158 } | |
| 159 | |
| 160 return success; | |
| 161 } | |
| 162 | |
| 163 bool Zip(const base::FilePath& src_dir, const base::FilePath& dest_file, | |
| 164 bool include_hidden_files) { | |
| 165 if (include_hidden_files) { | |
| 166 return ZipWithFilterCallback( | |
| 167 src_dir, dest_file, base::Bind(&ExcludeNoFilesFilter)); | |
| 168 } else { | |
| 169 return ZipWithFilterCallback( | |
| 170 src_dir, dest_file, base::Bind(&ExcludeHiddenFilesFilter)); | |
| 171 } | |
| 172 } | |
| 173 | |
| 174 #if defined(OS_POSIX) | |
| 175 bool ZipFiles(const base::FilePath& src_dir, | |
| 176 const std::vector<base::FilePath>& src_relative_paths, | |
| 177 int dest_fd) { | |
| 178 DCHECK(file_util::DirectoryExists(src_dir)); | |
| 179 zipFile zip_file = internal::OpenFdForZipping(dest_fd, APPEND_STATUS_CREATE); | |
| 180 | |
| 181 if (!zip_file) { | |
| 182 DLOG(ERROR) << "couldn't create file for fd " << dest_fd; | |
| 183 return false; | |
| 184 } | |
| 185 | |
| 186 bool success = true; | |
| 187 for (std::vector<base::FilePath>::const_iterator iter = | |
| 188 src_relative_paths.begin(); | |
| 189 iter != src_relative_paths.end(); ++iter) { | |
| 190 const base::FilePath& path = src_dir.Append(*iter); | |
| 191 if (!AddEntryToZip(zip_file, path, src_dir)) { | |
| 192 // TODO(hshi): clean up the partial zip file when error occurs. | |
| 193 success = false; | |
| 194 break; | |
| 195 } | |
| 196 } | |
| 197 | |
| 198 if (ZIP_OK != zipClose(zip_file, NULL)) { | |
| 199 DLOG(ERROR) << "Error closing zip file for fd " << dest_fd; | |
| 200 success = false; | |
| 201 } | |
| 202 | |
| 203 return success; | |
| 204 } | |
| 205 #endif // defined(OS_POSIX) | |
| 206 | |
| 207 } // namespace zip | |
| OLD | NEW |