15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "third_party/zlib/google/zip.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <string> 85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <vector> 95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h" 11effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "base/files/file.h" 12868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/files/file_enumerator.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 145e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/string16.h" 155e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/string_util.h" 16c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "third_party/zlib/google/zip_internal.h" 17c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "third_party/zlib/google/zip_reader.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(USE_SYSTEM_MINIZIP) 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <minizip/unzip.h> 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <minizip/zip.h> 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/zlib/contrib/minizip/unzip.h" 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/zlib/contrib/minizip/zip.h" 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool AddFileToZip(zipFile zip_file, const base::FilePath& src_dir) { 30effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch base::File file(src_dir, base::File::FLAG_OPEN | base::File::FLAG_READ); 31effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch if (!file.IsValid()) { 32effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch DLOG(ERROR) << "Could not open file for path " << src_dir.value(); 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int num_bytes; 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char buf[zip::internal::kZipBufSize]; 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) do { 39effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch num_bytes = file.ReadAtCurrentPos(buf, zip::internal::kZipBufSize); 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (num_bytes > 0) { 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ZIP_OK != zipWriteInFileInZip(zip_file, buf, num_bytes)) { 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DLOG(ERROR) << "Could not write data to zip for path " 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << src_dir.value(); 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } while (num_bytes > 0); 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool AddEntryToZip(zipFile zip_file, const base::FilePath& path, 532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::FilePath& root_path) { 54a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::FilePath relative_path; 55a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) bool result = root_path.AppendRelativePath(path, &relative_path); 56a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) DCHECK(result); 57a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) std::string str_path = relative_path.AsUTF8Unsafe(); 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN) 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ReplaceSubstringsAfterOffset(&str_path, 0u, "\\", "/"); 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 627dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch bool is_directory = base::DirectoryExists(path); 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (is_directory) 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) str_path += "/"; 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 66010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) zip_fileinfo file_info = zip::internal::GetFileInfoForZipping(path); 67010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if (!zip::internal::ZipOpenNewFileInZip(zip_file, str_path, &file_info)) 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool success = true; 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!is_directory) { 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) success = AddFileToZip(zip_file, path); 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ZIP_OK != zipCloseFileInZip(zip_file)) { 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DLOG(ERROR) << "Could not close zip file entry " << str_path; 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return success; 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool ExcludeNoFilesFilter(const base::FilePath& file_path) { 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool ExcludeHiddenFilesFilter(const base::FilePath& file_path) { 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return file_path.BaseName().value()[0] != '.'; 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace zip { 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool Unzip(const base::FilePath& src_file, const base::FilePath& dest_dir) { 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ZipReader reader; 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!reader.Open(src_file)) { 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DLOG(WARNING) << "Failed to open " << src_file.value(); 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (reader.HasMore()) { 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!reader.OpenCurrentEntryInZip()) { 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DLOG(WARNING) << "Failed to open the current file in zip"; 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (reader.current_entry_info()->is_unsafe()) { 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DLOG(WARNING) << "Found an unsafe file in zip " 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << reader.current_entry_info()->file_path().value(); 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!reader.ExtractCurrentEntryIntoDirectory(dest_dir)) { 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DLOG(WARNING) << "Failed to extract " 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << reader.current_entry_info()->file_path().value(); 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!reader.AdvanceToNextEntry()) { 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DLOG(WARNING) << "Failed to advance to the next file"; 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool ZipWithFilterCallback(const base::FilePath& src_dir, 1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::FilePath& dest_file, 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const FilterCallback& filter_cb) { 1277dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch DCHECK(base::DirectoryExists(src_dir)); 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) zipFile zip_file = internal::OpenForZipping(dest_file.AsUTF8Unsafe(), 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) APPEND_STATUS_CREATE); 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!zip_file) { 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DLOG(WARNING) << "couldn't create file " << dest_file.value(); 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool success = true; 138868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) base::FileEnumerator file_enumerator(src_dir, true /* recursive */, 139868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES); 1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (base::FilePath path = file_enumerator.Next(); !path.value().empty(); 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) path = file_enumerator.Next()) { 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!filter_cb.Run(path)) { 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!AddEntryToZip(zip_file, path, src_dir)) { 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) success = false; 148010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) break; 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ZIP_OK != zipClose(zip_file, NULL)) { 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DLOG(ERROR) << "Error closing zip file " << dest_file.value(); 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return success; 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool Zip(const base::FilePath& src_dir, const base::FilePath& dest_file, 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool include_hidden_files) { 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (include_hidden_files) { 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ZipWithFilterCallback( 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) src_dir, dest_file, base::Bind(&ExcludeNoFilesFilter)); 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ZipWithFilterCallback( 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) src_dir, dest_file, base::Bind(&ExcludeHiddenFilesFilter)); 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(OS_POSIX) 1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool ZipFiles(const base::FilePath& src_dir, 1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::vector<base::FilePath>& src_relative_paths, 1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int dest_fd) { 1757dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch DCHECK(base::DirectoryExists(src_dir)); 1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) zipFile zip_file = internal::OpenFdForZipping(dest_fd, APPEND_STATUS_CREATE); 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!zip_file) { 1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DLOG(ERROR) << "couldn't create file for fd " << dest_fd; 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool success = true; 1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (std::vector<base::FilePath>::const_iterator iter = 1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) src_relative_paths.begin(); 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) iter != src_relative_paths.end(); ++iter) { 1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::FilePath& path = src_dir.Append(*iter); 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!AddEntryToZip(zip_file, path, src_dir)) { 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(hshi): clean up the partial zip file when error occurs. 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) success = false; 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ZIP_OK != zipClose(zip_file, NULL)) { 1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DLOG(ERROR) << "Error closing zip file for fd " << dest_fd; 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) success = false; 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return success; 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif // defined(OS_POSIX) 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace zip 205