1 // Copyright (c) 2012 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.
5 #include "third_party/zlib/google/zip.h"
10 #include "base/bind.h"
11 #include "base/files/file.h"
12 #include "base/files/file_enumerator.h"
13 #include "base/logging.h"
14 #include "base/strings/string16.h"
15 #include "base/strings/string_util.h"
16 #include "third_party/zlib/google/zip_internal.h"
17 #include "third_party/zlib/google/zip_reader.h"
19 #if defined(USE_SYSTEM_MINIZIP)
20 #include <minizip/unzip.h>
21 #include <minizip/zip.h>
23 #include "third_party/zlib/contrib/minizip/unzip.h"
24 #include "third_party/zlib/contrib/minizip/zip.h"
29 bool AddFileToZip(zipFile zip_file
, const base::FilePath
& src_dir
) {
30 base::File
file(src_dir
, base::File::FLAG_OPEN
| base::File::FLAG_READ
);
31 if (!file
.IsValid()) {
32 DLOG(ERROR
) << "Could not open file for path " << src_dir
.value();
37 char buf
[zip::internal::kZipBufSize
];
39 num_bytes
= file
.ReadAtCurrentPos(buf
, zip::internal::kZipBufSize
);
41 if (ZIP_OK
!= zipWriteInFileInZip(zip_file
, buf
, num_bytes
)) {
42 DLOG(ERROR
) << "Could not write data to zip for path "
47 } while (num_bytes
> 0);
52 bool AddEntryToZip(zipFile zip_file
, const base::FilePath
& path
,
53 const base::FilePath
& root_path
) {
54 base::FilePath relative_path
;
55 bool result
= root_path
.AppendRelativePath(path
, &relative_path
);
57 std::string str_path
= relative_path
.AsUTF8Unsafe();
59 ReplaceSubstringsAfterOffset(&str_path
, 0u, "\\", "/");
62 bool is_directory
= base::DirectoryExists(path
);
66 zip_fileinfo file_info
= zip::internal::GetFileInfoForZipping(path
);
67 if (!zip::internal::ZipOpenNewFileInZip(zip_file
, str_path
, &file_info
))
72 success
= AddFileToZip(zip_file
, path
);
75 if (ZIP_OK
!= zipCloseFileInZip(zip_file
)) {
76 DLOG(ERROR
) << "Could not close zip file entry " << str_path
;
83 bool ExcludeNoFilesFilter(const base::FilePath
& file_path
) {
87 bool ExcludeHiddenFilesFilter(const base::FilePath
& file_path
) {
88 return file_path
.BaseName().value()[0] != '.';
95 bool Unzip(const base::FilePath
& src_file
, const base::FilePath
& dest_dir
) {
97 if (!reader
.Open(src_file
)) {
98 DLOG(WARNING
) << "Failed to open " << src_file
.value();
101 while (reader
.HasMore()) {
102 if (!reader
.OpenCurrentEntryInZip()) {
103 DLOG(WARNING
) << "Failed to open the current file in zip";
106 if (reader
.current_entry_info()->is_unsafe()) {
107 DLOG(WARNING
) << "Found an unsafe file in zip "
108 << reader
.current_entry_info()->file_path().value();
111 if (!reader
.ExtractCurrentEntryIntoDirectory(dest_dir
)) {
112 DLOG(WARNING
) << "Failed to extract "
113 << reader
.current_entry_info()->file_path().value();
116 if (!reader
.AdvanceToNextEntry()) {
117 DLOG(WARNING
) << "Failed to advance to the next file";
124 bool ZipWithFilterCallback(const base::FilePath
& src_dir
,
125 const base::FilePath
& dest_file
,
126 const FilterCallback
& filter_cb
) {
127 DCHECK(base::DirectoryExists(src_dir
));
129 zipFile zip_file
= internal::OpenForZipping(dest_file
.AsUTF8Unsafe(),
130 APPEND_STATUS_CREATE
);
133 DLOG(WARNING
) << "couldn't create file " << dest_file
.value();
138 base::FileEnumerator
file_enumerator(src_dir
, true /* recursive */,
139 base::FileEnumerator::FILES
| base::FileEnumerator::DIRECTORIES
);
140 for (base::FilePath path
= file_enumerator
.Next(); !path
.value().empty();
141 path
= file_enumerator
.Next()) {
142 if (!filter_cb
.Run(path
)) {
146 if (!AddEntryToZip(zip_file
, path
, src_dir
)) {
152 if (ZIP_OK
!= zipClose(zip_file
, NULL
)) {
153 DLOG(ERROR
) << "Error closing zip file " << dest_file
.value();
160 bool Zip(const base::FilePath
& src_dir
, const base::FilePath
& dest_file
,
161 bool include_hidden_files
) {
162 if (include_hidden_files
) {
163 return ZipWithFilterCallback(
164 src_dir
, dest_file
, base::Bind(&ExcludeNoFilesFilter
));
166 return ZipWithFilterCallback(
167 src_dir
, dest_file
, base::Bind(&ExcludeHiddenFilesFilter
));
171 #if defined(OS_POSIX)
172 bool ZipFiles(const base::FilePath
& src_dir
,
173 const std::vector
<base::FilePath
>& src_relative_paths
,
175 DCHECK(base::DirectoryExists(src_dir
));
176 zipFile zip_file
= internal::OpenFdForZipping(dest_fd
, APPEND_STATUS_CREATE
);
179 DLOG(ERROR
) << "couldn't create file for fd " << dest_fd
;
184 for (std::vector
<base::FilePath
>::const_iterator iter
=
185 src_relative_paths
.begin();
186 iter
!= src_relative_paths
.end(); ++iter
) {
187 const base::FilePath
& path
= src_dir
.Append(*iter
);
188 if (!AddEntryToZip(zip_file
, path
, src_dir
)) {
189 // TODO(hshi): clean up the partial zip file when error occurs.
195 if (ZIP_OK
!= zipClose(zip_file
, NULL
)) {
196 DLOG(ERROR
) << "Error closing zip file for fd " << dest_fd
;
202 #endif // defined(OS_POSIX)