From 61822a005c9666851a849cf71efb84314db48edf Mon Sep 17 00:00:00 2001 From: Olaf Wintermann Date: Wed, 24 Jun 2026 20:53:15 +0200 Subject: [PATCH] improve dav error handling --- dav-rs/src/dav/ffi.rs | 25 +++++++ dav-rs/src/dav/resource.rs | 138 ++++++++++++++++++++++++++----------- dav-rs/src/dav/session.rs | 73 +++++++++++++++++++- libidav/session.c | 8 +++ libidav/webdav.h | 3 + 5 files changed, 206 insertions(+), 41 deletions(-) diff --git a/dav-rs/src/dav/ffi.rs b/dav-rs/src/dav/ffi.rs index 2ac0391..ed2d100 100644 --- a/dav-rs/src/dav/ffi.rs +++ b/dav-rs/src/dav/ffi.rs @@ -68,3 +68,28 @@ pub type DavReadFunc = Option libc::size_t>; pub type DavSeekFunc = Option c_int>; +#[repr(C)] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum DavError { + DavOk = 0, + DavError, + DavNotFound, + DavUnauthorized, + DavForbidden, + DavMethodNotAllowed, + DavConflict, + DavLocked, + DavUnsupportedProtocol, + DavCouldntResolveProxy, + DavCouldntResolveHost, + DavCouldntConnect, + DavTimeout, + DavSslError, + DavQlError, + DavContentVerificationError, + DavPreconditionFailed, + DavRequestEntityTooLarge, + DavRequestUrlTooLong, + DavProxyAuthRequired, + DavNetAuthRequired, +} diff --git a/dav-rs/src/dav/resource.rs b/dav-rs/src/dav/resource.rs index c2e556f..536b434 100644 --- a/dav-rs/src/dav/resource.rs +++ b/dav-rs/src/dav/resource.rs @@ -36,7 +36,7 @@ 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; +use crate::dav::session::{get_session_error, DavError, Session}; pub struct Resource<'a> { pub base: ResourceRef<'a> @@ -155,27 +155,60 @@ impl<'a> ResourceRef<'a> { } } - pub fn exists(&self) -> bool { - unsafe { dav_resource_exists(self.ptr) != 0 } + pub fn exists(&self) -> Result { + let res = unsafe { dav_resource_exists(self.ptr) != 0 }; + if res { + Ok(res) + } else { + let err = unsafe { get_session_error((*self.ptr).session) }; + match err { + DavError::NotFound => Ok(false), + _ => Err(err), + } + } } - pub fn create(&self) -> bool { - unsafe { dav_resource_create(self.ptr) == 0 } + pub fn create(&self) -> Result<(), DavError> { + unsafe { + if dav_resource_create(self.ptr) == 0 { + Ok(()) + } else { + Err(get_session_error((*self.ptr).session)) + } + } } - pub fn delete(&self) -> bool { - unsafe { dav_resource_delete(self.ptr) == 0 } + pub fn delete(&self) -> Result<(), DavError> { + unsafe { + if dav_resource_delete(self.ptr) == 0 { + Ok(()) + } else { + Err(get_session_error((*self.ptr).session)) + } + } } - pub fn load(&self) -> bool { - unsafe { dav_load(self.ptr) == 0 } + pub fn load(&self) -> Result<(), DavError> { + unsafe { + if dav_load(self.ptr) == 0 { + Ok(()) + } else { + Err(get_session_error((*self.ptr).session)) + } + } } - pub fn store(&self) -> bool { - unsafe { dav_store(self.ptr) == 0 } + pub fn store(&self) -> Result<(), DavError> { + unsafe { + if dav_store(self.ptr) == 0 { + Ok(()) + } else { + Err(get_session_error((*self.ptr).session)) + } + } } - pub fn store_with_data(&self, data: &[u8]) -> bool { + pub fn store_with_data(&self, data: &[u8]) -> Result<(), DavError> { unsafe { dav_set_content_data( self.ptr, @@ -183,13 +216,15 @@ impl<'a> ResourceRef<'a> { data.len() as size_t, ); - let res = dav_store(self.ptr); - - res == 0 + if dav_store(self.ptr) == 0 { + Ok(()) + } else { + Err(get_session_error((*self.ptr).session)) + } } } - pub fn store_with_seekable_stream(&self, stream: &mut T) -> bool { + pub fn store_with_seekable_stream(&self, stream: &mut T) -> Result<(), DavError> { let mut wrapper = DavSeekableInputStream { inner: stream }; unsafe { @@ -200,13 +235,15 @@ impl<'a> ResourceRef<'a> { Some(seek_callback::), ); - let res = dav_store(self.ptr); - - res == 0 + if dav_store(self.ptr) == 0 { + Ok(()) + } else { + Err(get_session_error((*self.ptr).session)) + } } } - pub fn store_with_stream(&self, stream: &mut T) -> bool { + pub fn store_with_stream(&self, stream: &mut T) -> Result<(), DavError> { let mut wrapper = DavInputStream { inner: stream }; unsafe { @@ -217,36 +254,57 @@ impl<'a> ResourceRef<'a> { None, ); - let res = dav_store(self.ptr); - - res == 0 + if dav_store(self.ptr) == 0 { + Ok(()) + } else { + Err(get_session_error((*self.ptr).session)) + } } } - pub fn get_content(&self, stream: &mut T) -> bool { + pub fn get_content(&self, stream: &mut T) -> Result<(), DavError> { 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::), - ) - }; - - result == 0 + unsafe { + let result = dav_get_content( + self.ptr, + &mut wrapper as *mut _ as *mut c_void, + Some(write_callback::)); + if result == 0 { + Ok(()) + } else { + Err(get_session_error((*self.ptr).session)) + } + } } - pub fn lock(&self) -> bool { - unsafe { dav_lock(self.ptr) == 0 } + pub fn lock(&self) -> Result<(), DavError> { + unsafe { + if dav_lock(self.ptr) == 0 { + Ok(()) + } else { + Err(get_session_error((*self.ptr).session)) + } + } } - pub fn lock_t(&self, timeout: u64) -> bool { - unsafe { dav_lock_t(self.ptr, timeout as libc::time_t) == 0 } + pub fn lock_t(&self, timeout: u64) -> Result<(), DavError> { + unsafe { + if dav_lock_t(self.ptr, timeout as libc::time_t) == 0 { + Ok(()) + } else { + Err(get_session_error((*self.ptr).session)) + } + } } - pub fn unlock(&self) -> bool { - unsafe { dav_unlock(self.ptr) == 0 } + pub fn unlock(&self) -> Result<(), DavError> { + unsafe { + if dav_unlock(self.ptr) == 0 { + Ok(()) + } else { + Err(get_session_error((*self.ptr).session)) + } + } } } diff --git a/dav-rs/src/dav/session.rs b/dav-rs/src/dav/session.rs index f63c41e..d962d43 100644 --- a/dav-rs/src/dav/session.rs +++ b/dav-rs/src/dav/session.rs @@ -27,7 +27,7 @@ */ #![allow(dead_code)] -use std::ffi::{c_char, CString}; +use std::ffi::{c_char, CStr, CString}; use crate::dav::context::DavContext; use crate::dav::ffi; @@ -61,6 +61,10 @@ impl Session { dav_session_set_auth(self.ptr, user_cstr.as_ptr(), password_cstr.as_ptr()); } } + + pub fn get_error(&self) -> DavError { + get_session_error(self.ptr) + } } @@ -81,6 +85,70 @@ impl DavContext { } } +pub fn get_session_error(sn: *const ffi::DavSession) -> DavError { + let err = unsafe { dav_session_get_error(sn) }; + let errstr = unsafe { dav_session_get_errorstr(sn) }; + + match err { + ffi::DavError::DavOk => DavError::Ok, + ffi::DavError::DavError => { + let str = if errstr.is_null() { + String::new() + } else { + unsafe { + CStr::from_ptr(errstr) + .to_string_lossy() + .into_owned() + } + }; + DavError::Error(str) + }, + ffi::DavError::DavNotFound => DavError::NotFound, + ffi::DavError::DavUnauthorized => DavError::Unauthorized, + ffi::DavError::DavForbidden => DavError::Forbidden, + ffi::DavError::DavMethodNotAllowed => DavError::MethodNotAllowed, + ffi::DavError::DavConflict => DavError::Conflict, + ffi::DavError::DavLocked => DavError::Locked, + ffi::DavError::DavUnsupportedProtocol => DavError::UnsupportedProtocol, + ffi::DavError::DavCouldntResolveProxy => DavError::CouldntResolveProxy, + ffi::DavError::DavCouldntResolveHost => DavError::CouldntResolveHost, + ffi::DavError::DavCouldntConnect => DavError::CouldntConnect, + ffi::DavError::DavTimeout => DavError::Timeout, + ffi::DavError::DavSslError => DavError::SslError, + ffi::DavError::DavQlError => DavError::QlError, + ffi::DavError::DavContentVerificationError => DavError::ContentVerificationError, + ffi::DavError::DavPreconditionFailed => DavError::PreconditionFailed, + ffi::DavError::DavRequestEntityTooLarge => DavError::RequestEntityTooLarge, + ffi::DavError::DavRequestUrlTooLong => DavError::RequestUrlTooLong, + ffi::DavError::DavProxyAuthRequired => DavError::ProxyAuthRequired, + ffi::DavError::DavNetAuthRequired => DavError::NetAuthRequired, + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum DavError { + Ok, + Error(String), + NotFound, + Unauthorized, + Forbidden, + MethodNotAllowed, + Conflict, + Locked, + UnsupportedProtocol, + CouldntResolveProxy, + CouldntResolveHost, + CouldntConnect, + Timeout, + SslError, + QlError, + ContentVerificationError, + PreconditionFailed, + RequestEntityTooLarge, + RequestUrlTooLong, + ProxyAuthRequired, + NetAuthRequired, +} unsafe extern "C" { fn dav_session_new(ctx: *mut ffi::DavContext, base_url: *const libc::c_char) -> *mut ffi::DavSession; @@ -88,4 +156,7 @@ unsafe extern "C" { fn dav_session_unref(sn: *mut ffi::DavSession); fn dav_session_clone(sn: *mut ffi::DavSession) -> *mut ffi::DavSession; fn dav_session_set_auth(sn: *mut ffi::DavSession, user: *const c_char, password: *const c_char); + + fn dav_session_get_error(sn: *const ffi::DavSession) -> ffi::DavError; + fn dav_session_get_errorstr(sn: *const ffi::DavSession) -> *const c_char; } \ No newline at end of file diff --git a/libidav/session.c b/libidav/session.c index e922593..4d1b6c5 100644 --- a/libidav/session.c +++ b/libidav/session.c @@ -359,6 +359,14 @@ void dav_session_set_errstr(DavSession *sn, const char *str) { sn->errorstr = errstr; } +DavError dav_session_get_error(DavSession *sn) { + return sn->error; +} + +const char* dav_session_get_errorstr(DavSession *sn) { + return sn->errorstr; +} + void dav_session_destroy(DavSession *sn) { // remove session from context DavContext *ctx = sn->context; diff --git a/libidav/webdav.h b/libidav/webdav.h index e1efa31..14f4160 100644 --- a/libidav/webdav.h +++ b/libidav/webdav.h @@ -305,6 +305,9 @@ void dav_session_enable_encryption(DavSession *sn, DavKey *key, int flags); void dav_session_set_authcallback(DavSession *sn, dav_auth_func func, void *userdata); void dav_session_set_progresscallback(DavSession *sn, dav_progress_func get, dav_progress_func put, void *userdata); +DavError dav_session_get_error(DavSession *sn); +const char* dav_session_get_errorstr(DavSession *sn); + void dav_session_destroy(DavSession *sn); void dav_session_destructor(DavSession *sn); -- 2.52.0