| // 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/check.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 |