blob: 15401d1c6ab9198da88157c27fe934571fa6f4ee [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/file_copy_progress.h"
#include <algorithm>
#include <base/logging.h>
namespace smbprovider {
namespace {
const off_t kDefaultIterationChunkSize = 4 * 1024 * 1024;
} // namespace
FileCopyProgress::FileCopyProgress(SambaInterface* samba_interface,
off_t iteration_chunk_size)
: samba_interface_(samba_interface),
iteration_chunk_size_(iteration_chunk_size) {}
FileCopyProgress::FileCopyProgress(SambaInterface* samba_interface)
: FileCopyProgress(samba_interface, kDefaultIterationChunkSize) {}
FileCopyProgress::~FileCopyProgress() = default;
bool FileCopyProgress::StartCopy(const std::string& source,
const std::string& target,
int32_t* error) {
DCHECK(!is_started_);
is_started_ = true;
if (!OpenCopySource(source, error) || !OpenCopyTarget(target, error)) {
FinishCopy();
return false;
}
struct stat source_stat;
const int32_t stat_result =
samba_interface_->GetEntryStatus(source, &source_stat);
if (stat_result != 0) {
FinishCopy();
*error = stat_result;
return false;
}
if (source_stat.st_size == 0) {
// Empty file.
FinishCopy();
*error = 0;
return false;
}
bytes_remaining_ = source_stat.st_size;
return ContinueCopy(error);
}
bool FileCopyProgress::ContinueCopy(int32_t* error) {
DCHECK(is_started_);
DCHECK(!is_done_);
const off_t bytes_to_splice =
std::min(bytes_remaining_, iteration_chunk_size_);
DCHECK_GT(bytes_to_splice, 0);
off_t bytes_spliced;
int32_t result = samba_interface_->SpliceFile(
source_fd_, target_fd_, bytes_to_splice, &bytes_spliced);
if (result != 0) {
// The copy failed.
FinishCopy();
*error = result;
return false;
}
DCHECK_GE(bytes_remaining_, bytes_spliced);
bytes_remaining_ -= bytes_spliced;
if (bytes_remaining_ == 0) {
// The copy is done.
FinishCopy();
*error = 0;
return false;
}
// No error and there are |bytes_remaining_| so the copy should be continued.
return true;
}
bool FileCopyProgress::OpenCopySource(const std::string& file_path,
int32_t* error) {
*error = samba_interface_->OpenFile(file_path, O_RDONLY, &source_fd_);
if (*error != 0) {
return false;
}
return true;
}
bool FileCopyProgress::OpenCopyTarget(const std::string& file_path,
int32_t* error) {
*error = samba_interface_->CreateFile(file_path, &target_fd_);
if (*error != 0) {
return false;
}
return true;
}
void FileCopyProgress::CloseCopySourceAndTarget() {
int32_t result;
if (source_fd_ >= 0) {
result = samba_interface_->CloseFile(source_fd_);
}
if (target_fd_ >= 0) {
result = samba_interface_->CloseFile(target_fd_);
}
}
void FileCopyProgress::FinishCopy() {
is_done_ = true;
CloseCopySourceAndTarget();
}
} // namespace smbprovider