blob: afc3bf01b32eb016651f1b1941d1a2e8c1536f1f [file]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
use ::opendal as core;
use std::ffi::c_void;
use super::*;
/// \brief opendal_copier completes a long-running copy operation to
/// completion in a blocking manner. opendal_copier repeatedly calls a
/// copy operation until completion.
///
/// Internally, each copy step performs a unit of work and reports progress.
/// When copy completes, `has_next` returns false.
///
/// A "step" is one backend-defined unit of work. For backends that copy in
/// multiple requests (e.g. multipart copy), one step typically copies one chunk;
/// for backends that only support single-request copy, the entire copy happens
/// in a single step. The reported byte count is best-effort: a step may report
/// 0 bytes when the backend advances its state without a reliable byte delta.
///
/// Users can construct a copier by `opendal_operator_copier` or
/// `opendal_operator_copier_with`.
///
/// @see opendal_operator_copier()
/// @see opendal_copier_next()
#[repr(C)]
pub struct opendal_copier {
/// The pointer to the opendal::blocking::Copier in the Rust code.
/// Only used to check whether the copier is NULL.
inner: *mut c_void,
}
impl opendal_copier {
fn deref_mut(&mut self) -> &mut core::blocking::Copier {
// Safety: the inner should never be null once constructed
// The use-after-free is undefined behavior
unsafe { &mut *(self.inner as *mut core::blocking::Copier) }
}
}
impl opendal_copier {
pub(crate) fn new(copier: core::blocking::Copier) -> Self {
Self {
inner: Box::into_raw(Box::new(copier)) as _,
}
}
/// \brief Perform one step of the copy operation.
///
/// One step performs one backend-defined unit of work: typically one chunk for
/// backends that copy in multiple requests, or the entire copy for backends that
/// only support single-request copy.
///
/// Returns the number of bytes copied in this step (best-effort; may be 0 when
/// the backend advances without a reliable byte delta). When `has_next` is true
/// the caller should call this function again to continue the copy. When
/// `has_next` is false and `error` is null the copy has completed.
///
/// @see opendal_operator_copier()
#[no_mangle]
pub unsafe extern "C" fn opendal_copier_next(&mut self) -> opendal_result_copier_next {
match self.deref_mut().next() {
Some(Ok(n)) => opendal_result_copier_next {
size: n,
has_next: true,
error: std::ptr::null_mut(),
},
None => opendal_result_copier_next {
size: 0,
has_next: false,
error: std::ptr::null_mut(),
},
Some(Err(e)) => opendal_result_copier_next {
size: 0,
has_next: false,
error: opendal_error::new(e),
},
}
}
/// \brief Abort the pending copy operation.
///
/// Returns NULL if the abort succeeds, otherwise it contains the error code and
/// error message.
#[no_mangle]
pub unsafe extern "C" fn opendal_copier_abort(&mut self) -> *mut opendal_error {
if let Err(e) = self.deref_mut().abort() {
opendal_error::new(e)
} else {
std::ptr::null_mut()
}
}
/// \brief Free the heap memory used by the opendal_copier.
#[no_mangle]
pub unsafe extern "C" fn opendal_copier_free(ptr: *mut opendal_copier) {
unsafe {
if !ptr.is_null() {
drop(Box::from_raw((*ptr).inner as *mut core::blocking::Copier));
// A use-after-free crashes on NULL instead of reading stale memory.
(*ptr).inner = std::ptr::null_mut();
drop(Box::from_raw(ptr));
}
}
}
}