blob: 090011096438ce147f729cd32af7301140e2cba3 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/unzip_service/unzipper_impl.h"
#include "base/compiler_specific.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
#include "third_party/zlib/google/zip.h"
#include "third_party/zlib/google/zip_reader.h"
namespace unzip {
namespace {
// A writer delegate that reports errors instead of writing.
class DudWriterDelegate : public zip::WriterDelegate {
public:
DudWriterDelegate() {}
~DudWriterDelegate() override {}
// WriterDelegate methods:
bool PrepareOutput() override { return false; }
bool WriteBytes(const char* data, int num_bytes) override { return false; }
void SetTimeModified(const base::Time& time) override {}
private:
DISALLOW_COPY_AND_ASSIGN(DudWriterDelegate);
};
std::string PathToMojoString(const base::FilePath& path) {
#if defined(OS_WIN)
return base::WideToUTF8(path.value());
#else
return path.value();
#endif
}
// Modifies output_dir to point to the final directory.
bool CreateDirectory(filesystem::mojom::DirectoryPtr* output_dir,
const base::FilePath& path) {
filesystem::mojom::FileError err = filesystem::mojom::FileError::OK;
return (*output_dir)
->OpenDirectory(PathToMojoString(path), nullptr,
filesystem::mojom::kFlagOpenAlways, &err) &&
err == filesystem::mojom::FileError::OK;
}
std::unique_ptr<zip::WriterDelegate> MakeFileWriterDelegateNoParent(
filesystem::mojom::DirectoryPtr* output_dir,
const base::FilePath& path) {
auto file = std::make_unique<base::File>();
filesystem::mojom::FileError err;
if (!(*output_dir)
->OpenFileHandle(PathToMojoString(path),
filesystem::mojom::kFlagCreate |
filesystem::mojom::kFlagWrite |
filesystem::mojom::kFlagWriteAttributes,
&err, file.get()) ||
err != filesystem::mojom::FileError::OK) {
return std::make_unique<DudWriterDelegate>();
}
return std::make_unique<zip::FileWriterDelegate>(std::move(file));
}
std::unique_ptr<zip::WriterDelegate> MakeFileWriterDelegate(
filesystem::mojom::DirectoryPtr* output_dir,
const base::FilePath& path) {
if (path == path.BaseName())
return MakeFileWriterDelegateNoParent(output_dir, path);
filesystem::mojom::DirectoryPtr parent;
filesystem::mojom::FileError err;
if (!(*output_dir)
->OpenDirectory(PathToMojoString(path.DirName()),
mojo::MakeRequest(&parent),
filesystem::mojom::kFlagOpenAlways, &err) ||
err != filesystem::mojom::FileError::OK) {
return std::make_unique<DudWriterDelegate>();
}
return MakeFileWriterDelegateNoParent(&parent, path.BaseName());
}
bool FilterNoFiles(const base::FilePath& unused) {
return true;
}
} // namespace
UnzipperImpl::UnzipperImpl(
std::unique_ptr<service_manager::ServiceContextRef> service_ref)
: service_ref_(std::move(service_ref)) {}
UnzipperImpl::~UnzipperImpl() = default;
void UnzipperImpl::Unzip(base::File zip_file,
filesystem::mojom::DirectoryPtr output_dir,
UnzipCallback callback) {
DCHECK(zip_file.IsValid());
std::move(callback).Run(zip::UnzipWithFilterAndWriters(
zip_file.GetPlatformFile(),
base::BindRepeating(&MakeFileWriterDelegate, &output_dir),
base::BindRepeating(&CreateDirectory, &output_dir),
base::BindRepeating(&FilterNoFiles), false));
}
} // namespace unzip