- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / test / chromedriver / chrome / zip.cc
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/chrome/zip.h"
6
7 #include "base/bind.h"
8 #include "base/file_util.h"
9 #include "base/files/file_enumerator.h"
10 #include "base/logging.h"
11 #include "base/strings/string16.h"
12 #include "base/strings/string_util.h"
13 #include "chrome/test/chromedriver/chrome/zip_internal.h"
14 #include "chrome/test/chromedriver/chrome/zip_reader.h"
15 #include "net/base/file_stream.h"
16
17 #if defined(USE_SYSTEM_MINIZIP)
18 #include <minizip/unzip.h>
19 #include <minizip/zip.h>
20 #else
21 #include "third_party/zlib/contrib/minizip/unzip.h"
22 #include "third_party/zlib/contrib/minizip/zip.h"
23 #endif
24
25 namespace {
26
27 bool AddFileToZip(zipFile zip_file, const base::FilePath& src_dir) {
28   net::FileStream stream(NULL);
29   int flags = base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ;
30   if (stream.OpenSync(src_dir, flags) != 0) {
31     DLOG(ERROR) << "Could not open stream for path "
32                 << src_dir.value();
33     return false;
34   }
35
36   int num_bytes;
37   char buf[zip::internal::kZipBufSize];
38   do {
39     num_bytes = stream.ReadSync(buf, zip::internal::kZipBufSize);
40     if (num_bytes > 0) {
41       if (ZIP_OK != zipWriteInFileInZip(zip_file, buf, num_bytes)) {
42         DLOG(ERROR) << "Could not write data to zip for path "
43                     << src_dir.value();
44         return false;
45       }
46     }
47   } while (num_bytes > 0);
48
49   return true;
50 }
51
52 bool AddEntryToZip(zipFile zip_file, const base::FilePath& path,
53                    const base::FilePath& root_path) {
54   std::string str_path =
55       path.AsUTF8Unsafe().substr(root_path.value().length() + 1);
56 #if defined(OS_WIN)
57   ReplaceSubstringsAfterOffset(&str_path, 0u, "\\", "/");
58 #endif
59
60   bool is_directory = base::DirectoryExists(path);
61   if (is_directory)
62     str_path += "/";
63
64   if (ZIP_OK != zipOpenNewFileInZip(
65       zip_file, str_path.c_str(),
66       NULL, NULL, 0u, NULL, 0u, NULL,  // file info, extrafield local, length,
67                                        // extrafield global, length, comment
68       Z_DEFLATED, Z_DEFAULT_COMPRESSION)) {
69     DLOG(ERROR) << "Could not open zip file entry " << str_path;
70     return false;
71   }
72
73   bool success = true;
74   if (!is_directory) {
75     success = AddFileToZip(zip_file, path);
76   }
77
78   if (ZIP_OK != zipCloseFileInZip(zip_file)) {
79     DLOG(ERROR) << "Could not close zip file entry " << str_path;
80     return false;
81   }
82
83   return success;
84 }
85
86 bool ExcludeNoFilesFilter(const base::FilePath& file_path) {
87   return true;
88 }
89
90 bool ExcludeHiddenFilesFilter(const base::FilePath& file_path) {
91   return file_path.BaseName().value()[0] != '.';
92 }
93
94 }  // namespace
95
96 namespace zip {
97
98 bool Unzip(const base::FilePath& src_file, const base::FilePath& dest_dir) {
99   ZipReader reader;
100   if (!reader.Open(src_file)) {
101     DLOG(WARNING) << "Failed to open " << src_file.value();
102     return false;
103   }
104   while (reader.HasMore()) {
105     if (!reader.OpenCurrentEntryInZip()) {
106       DLOG(WARNING) << "Failed to open the current file in zip";
107       return false;
108     }
109     if (reader.current_entry_info()->is_unsafe()) {
110       DLOG(WARNING) << "Found an unsafe file in zip "
111                     << reader.current_entry_info()->file_path().value();
112       return false;
113     }
114     if (!reader.ExtractCurrentEntryIntoDirectory(dest_dir)) {
115       DLOG(WARNING) << "Failed to extract "
116                     << reader.current_entry_info()->file_path().value();
117       return false;
118     }
119     if (!reader.AdvanceToNextEntry()) {
120       DLOG(WARNING) << "Failed to advance to the next file";
121       return false;
122     }
123   }
124   return true;
125 }
126
127 bool ZipWithFilterCallback(const base::FilePath& src_dir,
128                            const base::FilePath& dest_file,
129                            const FilterCallback& filter_cb) {
130   DCHECK(base::DirectoryExists(src_dir));
131
132   zipFile zip_file = internal::OpenForZipping(dest_file.AsUTF8Unsafe(),
133                                               APPEND_STATUS_CREATE);
134
135   if (!zip_file) {
136     DLOG(WARNING) << "couldn't create file " << dest_file.value();
137     return false;
138   }
139
140   bool success = true;
141   base::FileEnumerator file_enumerator(src_dir, true /* recursive */,
142       base::FileEnumerator::FILES | base::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(base::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