blob: 2fcc11c648bf12f066603ecee6c6a89e228451c7 [file] [log] [blame]
// Copyright 2018 The Chromium OS 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 "smbprovider/recursive_copy_progress.h"
#include <base/logging.h>
#include <base/strings/string_util.h>
namespace smbprovider {
RecursiveCopyProgress::RecursiveCopyProgress(SambaInterface* samba_interface)
: samba_interface_(samba_interface) {}
RecursiveCopyProgress::~RecursiveCopyProgress() = default;
bool RecursiveCopyProgress::StartCopy(const std::string& source,
const std::string& target,
int32_t* error) {
DCHECK(!is_started_);
DCHECK(!is_done_);
source_root_ = source;
target_root_ = target;
is_started_ = true;
// Create an iterator for |source|.
CreateCopySourceIterator();
const int32_t it_result = copy_iterator_->Init();
if (it_result != 0 || copy_iterator_->IsDone()) {
// There was an error initializing the iterator.
*error = it_result;
FinishCopy();
return false;
}
return ContinueCopy(error);
}
bool RecursiveCopyProgress::ContinueCopy(int32_t* error) {
DCHECK(is_started_);
DCHECK(!is_done_);
DCHECK(!copy_iterator_->IsDone());
if (file_progress_) {
// Continue copying an in-progress file.
*error = ContinueFileCopy();
if (*error != 0) {
FinishCopy();
return false;
}
return true;
}
const DirectoryEntry& current = copy_iterator_->Get();
if (current.is_directory) {
*error = CreateDirectory(current);
} else {
*error = StartFileCopy(current);
}
if (*error != 0) {
FinishCopy();
return false;
}
const int32_t it_result = copy_iterator_->Next();
if (it_result != 0 || copy_iterator_->IsDone()) {
*error = it_result;
FinishCopy();
return false;
}
// Return true to indicate that ContinueCopy should be called again.
return true;
}
void RecursiveCopyProgress::FinishCopy() {
DCHECK(!is_done_);
is_done_ = true;
}
int32_t RecursiveCopyProgress::CreateDirectory(const DirectoryEntry& entry) {
return samba_interface_->CreateDirectory(
ConvertToTargetPath(entry.full_path));
}
int32_t RecursiveCopyProgress::StartFileCopy(const DirectoryEntry& entry) {
DCHECK(!file_progress_);
file_progress_ = std::make_unique<FileCopyProgress>(samba_interface_);
int32_t error;
const bool should_continue_copy = file_progress_->StartCopy(
entry.full_path, ConvertToTargetPath(entry.full_path), &error);
if (!should_continue_copy) {
file_progress_.reset();
}
return error;
}
int32_t RecursiveCopyProgress::ContinueFileCopy() {
DCHECK(file_progress_);
int32_t error;
const bool should_continue_copy = file_progress_->ContinueCopy(&error);
if (!should_continue_copy) {
// There is no more work to be done. Either the file copy completed
// successfully or encountered an error and failed.
file_progress_.reset();
}
return error;
}
std::string RecursiveCopyProgress::ConvertToTargetPath(
const std::string& full_source_path) const {
DCHECK(base::StartsWith(full_source_path, source_root_,
base::CompareCase::INSENSITIVE_ASCII));
return target_root_ + full_source_path.substr(source_root_.size());
}
void RecursiveCopyProgress::CreateCopySourceIterator() {
copy_iterator_ =
std::make_unique<PreDepthFirstIterator>(source_root_, samba_interface_);
}
} // namespace smbprovider