]> uap-core.de Git - note.git/commitdiff
add dav resource methods for loading/storing content
authorOlaf Wintermann <olaf.wintermann@gmail.com>
Mon, 22 Jun 2026 19:20:53 +0000 (21:20 +0200)
committerOlaf Wintermann <olaf.wintermann@gmail.com>
Mon, 22 Jun 2026 19:20:53 +0000 (21:20 +0200)
dav-rs/src/dav/ffi.rs
dav-rs/src/dav/resource.rs

index 93279af3711052bd4bed4cfef9fa8a9f88aba214..2ac03914ece5a2271ef133b144c941aac5b97f2f 100644 (file)
@@ -26,7 +26,7 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
-use std::ffi::{c_char, c_int, c_void};
+use std::ffi::{c_char, c_int, c_long, c_void};
 use libc::time_t;
 
 #[repr(C)]
@@ -63,3 +63,8 @@ pub struct DavResource {
     pub iscollection: c_int,
     pub exists: c_int,
 }
+
+pub type DavReadFunc = Option<extern "C" fn(data: *const c_void, size: libc::size_t, count: libc::size_t, stream: *mut c_void) -> libc::size_t>;
+pub type DavWriteFunc = Option<extern "C" fn(data: *const c_void, size: libc::size_t, count: libc::size_t, stream: *mut c_void) -> libc::size_t>;
+pub type DavSeekFunc = Option<extern "C" fn(stream: *mut c_void, offset: c_long, whence: c_int) -> c_int>;
+
index 25b85105fe687611e5a0a87d3435794393f7653e..084e5e737f2ea84edb00f8b49d4ce02d2d58fa4a 100644 (file)
  */
 #![allow(dead_code)]
 
-use std::ffi::{c_char, c_int, CString};
+use std::ffi::{c_char, c_int, c_long, c_void, CString};
+use std::io::{Read, Seek, SeekFrom, Write};
 use std::marker::PhantomData;
 use std::ops::Deref;
+use libc::size_t;
 use crate::dav::context::DavContext;
 use crate::dav::ffi;
+use crate::dav::ffi::{DavReadFunc, DavSeekFunc, DavWriteFunc};
 use crate::dav::session::Session;
 
 pub struct Resource<'a> {
@@ -111,8 +114,161 @@ impl<'a> ResourceRef<'a> {
         unsafe { dav_store(self.ptr) == 0 }
     }
 
-    pub fn as_ptr(&self) -> *mut ffi::DavResource {
-        self.ptr
+    pub fn store_with_data(&self, data: &[u8]) -> bool {
+        unsafe {
+            dav_set_content_data(
+                self.ptr,
+                data.as_ptr() as *const c_char,
+                data.len() as size_t,
+            );
+
+            let res = dav_store(self.ptr);
+
+            res == 0
+        }
+    }
+
+    pub fn store_with_seekable_stream<T: Read + Seek>(&self, stream: &mut T) -> bool {
+        let mut wrapper = DavSeekableInputStream { inner: stream };
+
+        unsafe {
+            dav_set_content(
+                self.ptr,
+                &mut wrapper as *mut _ as *mut c_void,
+                Some(seekable_read_callback::<T>),
+                Some(seek_callback::<T>),
+            );
+
+            let res = dav_store(self.ptr);
+
+            res == 0
+        }
+    }
+
+    pub fn store_with_stream<T: Read>(&self, stream: &mut T) -> bool {
+        let mut wrapper = DavInputStream { inner: stream };
+
+        unsafe {
+            dav_set_content(
+                self.ptr,
+                &mut wrapper as *mut _ as *mut c_void,
+                Some(read_callback::<T>),
+                None,
+            );
+
+            let res = dav_store(self.ptr);
+
+            res == 0
+        }
+    }
+
+    pub fn get_content<T: Write>(&self, stream: &mut T) -> bool {
+        let mut wrapper = DavOutputStream { inner: stream };
+
+        let result = unsafe {
+            dav_get_content(
+                self.ptr,
+                &mut wrapper as *mut _ as *mut c_void,
+                Some(write_callback::<T>),
+            )
+        };
+
+        result == 0
+    }
+}
+
+
+struct DavSeekableInputStream<'a, T: Read + Seek> {
+    inner: &'a mut T,
+}
+
+struct DavInputStream<'a, T: Read> {
+    inner: &'a mut T,
+}
+
+
+fn do_read<T: Read>(
+    ptr: *const c_void,
+    size: size_t,
+    nmemb: size_t,
+    stream: &mut T) -> size_t
+{
+    unsafe {
+        let len = size * nmemb;
+        let out = std::slice::from_raw_parts_mut(ptr as *mut u8, len);
+
+        match stream.read(out) {
+            Ok(n) => n,
+            Err(_) => 0,
+        }
+    }
+}
+
+extern "C" fn seekable_read_callback<T: Read + Seek>(
+    ptr: *const c_void,
+    size: size_t,
+    nmemb: size_t,
+    stream: *mut c_void,
+) -> size_t {
+    unsafe {
+        let stream = &mut *(stream as *mut DavSeekableInputStream<T>);
+        do_read(ptr, size, nmemb, stream.inner)
+    }
+}
+
+extern "C" fn read_callback<T: Read>(
+    ptr: *const c_void,
+    size: size_t,
+    nmemb: size_t,
+    stream: *mut c_void,
+) -> size_t {
+    unsafe {
+        let stream = &mut *(stream as *mut DavInputStream<T>);
+        do_read(ptr, size, nmemb, stream.inner)
+    }
+}
+
+
+extern "C" fn seek_callback<T: Read + Seek>(
+    stream: *mut c_void,
+    offset: c_long,
+    whence: c_int,
+) -> c_int {
+    unsafe {
+        let stream = &mut *(stream as *mut DavSeekableInputStream<T>);
+
+        let pos = match whence {
+            0 => SeekFrom::Start(offset as u64),
+            1 => SeekFrom::Current(offset as i64),
+            2 => SeekFrom::End(offset as i64),
+            _ => return -1,
+        };
+
+        stream.inner.seek(pos).map(|_| 0).unwrap_or(-1)
+    }
+}
+
+struct DavOutputStream<T: Write> {
+    inner: T,
+}
+
+
+extern "C" fn write_callback<T: Write>(
+    data: *const c_void,
+    size: size_t,
+    nmemb: size_t,
+    stream: *mut c_void,
+) -> size_t {
+    unsafe {
+        let stream = &mut *(stream as *mut DavOutputStream<T>);
+
+        let total_bytes = size * nmemb;
+        let buf = std::slice::from_raw_parts(data as *const u8, total_bytes);
+
+        match stream.inner.write_all(buf) {
+            Ok(_) => nmemb, // C expects "items written"
+            Err(_) => 0,
+        }
     }
 }
 
@@ -169,4 +325,8 @@ unsafe extern "C" {
 
     fn dav_load(res: *mut ffi::DavResource) -> c_int;
     fn dav_store(res: *mut ffi::DavResource) -> c_int;
+
+    fn dav_get_content(res: *mut ffi::DavResource, stream: *mut c_void, write_func: DavWriteFunc) -> c_int;
+    fn dav_set_content(res: *mut ffi::DavResource, stream: *mut c_void, read: DavReadFunc, seek: DavSeekFunc);
+    fn dav_set_content_data(res: *mut ffi::DavResource, content: *const c_char, length: size_t);
 }
\ No newline at end of file