Merge pull request #292 from link2xt/dc_get_abs_path_safe

Implement dc_get_abs_path_safe
This commit is contained in:
Friedel Ziegelmayer
2019-08-08 12:28:19 +02:00
committed by GitHub
3 changed files with 84 additions and 158 deletions

View File

@@ -1,5 +1,3 @@
use std::ffi::CString;
use strum::{EnumProperty, IntoEnumIterator}; use strum::{EnumProperty, IntoEnumIterator};
use strum_macros::{AsRefStr, Display, EnumIter, EnumProperty, EnumString}; use strum_macros::{AsRefStr, Display, EnumIter, EnumProperty, EnumString};
@@ -9,7 +7,6 @@ use crate::dc_job::*;
use crate::dc_tools::*; use crate::dc_tools::*;
use crate::error::Error; use crate::error::Error;
use crate::stock::StockMessage; use crate::stock::StockMessage;
use crate::x::*;
/// The available configuration keys. /// The available configuration keys.
#[derive( #[derive(
@@ -72,15 +69,7 @@ impl Context {
let value = match key { let value = match key {
Config::Selfavatar => { Config::Selfavatar => {
let rel_path = self.sql.get_config(self, key); let rel_path = self.sql.get_config(self, key);
rel_path.map(|p| { rel_path.map(|p| dc_get_abs_path_safe(self, &p).to_str().unwrap().to_string())
let v = unsafe {
let n = CString::yolo(p);
dc_get_abs_path(self, n.as_ptr())
};
let r = to_string(v);
unsafe { free(v as *mut _) };
r
})
} }
Config::SysVersion => Some(std::str::from_utf8(DC_VERSION_STR).unwrap().into()), Config::SysVersion => Some(std::str::from_utf8(DC_VERSION_STR).unwrap().into()),
Config::SysMsgsizeMaxRecommended => Some(format!("{}", 24 * 1024 * 1024 / 4 * 3)), Config::SysMsgsizeMaxRecommended => Some(format!("{}", 24 * 1024 * 1024 / 4 * 3)),

View File

@@ -1036,6 +1036,26 @@ pub unsafe fn dc_get_filemeta(
0 0
} }
/// Expand paths relative to $BLOBDIR into absolute paths.
///
/// If `path` starts with "$BLOBDIR", replaces it with the blobdir path.
/// Otherwise, returns path as is.
pub fn dc_get_abs_path_safe<P: AsRef<std::path::Path>>(
context: &Context,
path: P,
) -> std::path::PathBuf {
let p: &std::path::Path = path.as_ref();
if let Ok(p) = p.strip_prefix("$BLOBDIR") {
assert!(
context.has_blobdir(),
"Expected context to have blobdir to substitute $BLOBDIR",
);
std::path::PathBuf::from(as_str(context.get_blobdir())).join(p)
} else {
p.into()
}
}
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub unsafe fn dc_get_abs_path( pub unsafe fn dc_get_abs_path(
context: &Context, context: &Context,
@@ -1066,137 +1086,79 @@ pub unsafe fn dc_get_abs_path(
pathNfilename_abs pathNfilename_abs
} }
#[allow(non_snake_case)] pub fn dc_file_exist(context: &Context, path: *const libc::c_char) -> libc::c_int {
pub unsafe fn dc_file_exist(context: &Context, pathNfilename: *const libc::c_char) -> libc::c_int { dc_get_abs_path_safe(context, as_path(path)).exists() as libc::c_int
let pathNfilename_abs = dc_get_abs_path(context, pathNfilename);
if pathNfilename_abs.is_null() {
return 0;
}
let exist = {
let p = std::path::Path::new(as_str(pathNfilename_abs));
p.exists()
};
free(pathNfilename_abs as *mut libc::c_void);
exist as libc::c_int
} }
#[allow(non_snake_case)] pub fn dc_get_filebytes(context: &Context, path: *const libc::c_char) -> uint64_t {
pub unsafe fn dc_get_filebytes(context: &Context, pathNfilename: *const libc::c_char) -> uint64_t { let path_abs = dc_get_abs_path_safe(context, as_path(path));
let pathNfilename_abs = dc_get_abs_path(context, pathNfilename); match fs::metadata(&path_abs) {
if pathNfilename_abs.is_null() { Ok(meta) => meta.len() as uint64_t,
return 0; Err(_err) => 0,
} }
let p = std::ffi::CStr::from_ptr(pathNfilename_abs)
.to_str()
.unwrap();
let filebytes = match fs::metadata(p) {
Ok(meta) => meta.len(),
Err(_err) => {
return 0;
}
};
free(pathNfilename_abs as *mut libc::c_void);
filebytes as uint64_t
} }
#[allow(non_snake_case)] pub fn dc_delete_file(context: &Context, path: *const libc::c_char) -> libc::c_int {
pub unsafe fn dc_delete_file(context: &Context, pathNfilename: *const libc::c_char) -> libc::c_int { let path = as_path(path);
let mut success: libc::c_int = 0i32; let path_abs = dc_get_abs_path_safe(context, path);
let pathNfilename_abs = dc_get_abs_path(context, pathNfilename); let res = if path_abs.is_file() {
if pathNfilename_abs.is_null() { fs::remove_file(path_abs)
return 0;
}
let p = std::path::Path::new(
std::ffi::CStr::from_ptr(pathNfilename_abs)
.to_str()
.unwrap(),
);
let res = if p.is_file() {
fs::remove_file(p)
} else { } else {
fs::remove_dir_all(p) fs::remove_dir_all(path_abs)
}; };
match res { match res {
Ok(_) => { Ok(_) => 1,
success = 1;
}
Err(_err) => { Err(_err) => {
warn!(context, 0, "Cannot delete \"{}\".", as_str(pathNfilename),); warn!(context, 0, "Cannot delete \"{}\".", path.display());
0
} }
} }
free(pathNfilename_abs as *mut libc::c_void);
success
} }
#[allow(non_snake_case)] pub fn dc_copy_file(
pub unsafe fn dc_copy_file(
context: &Context, context: &Context,
src: *const libc::c_char, src: *const libc::c_char,
dest: *const libc::c_char, dest: *const libc::c_char,
) -> libc::c_int { ) -> libc::c_int {
let mut success = 0; let src = as_path(src);
let dest = as_path(dest);
let src_abs = dc_get_abs_path(context, src); let src_abs = dc_get_abs_path_safe(context, src);
let dest_abs = dc_get_abs_path(context, dest); let dest_abs = dc_get_abs_path_safe(context, dest);
match fs::copy(&src_abs, &dest_abs) {
if src_abs.is_null() || dest_abs.is_null() { Ok(_) => 1,
return 0;
}
let src_p = std::ffi::CStr::from_ptr(src_abs).to_str().unwrap();
let dest_p = std::ffi::CStr::from_ptr(dest_abs).to_str().unwrap();
match fs::copy(src_p, dest_p) {
Ok(_) => {
success = 1;
}
Err(_) => { Err(_) => {
error!(context, 0, "Cannot copy \"{}\" to \"{}\".", src_p, dest_p,); error!(
context,
0,
"Cannot copy \"{}\" to \"{}\".",
src.display(),
dest.display(),
);
0
} }
} }
free(src_abs as *mut libc::c_void);
free(dest_abs as *mut libc::c_void);
success
} }
#[allow(non_snake_case)] pub fn dc_create_folder(context: &Context, path: *const libc::c_char) -> libc::c_int {
pub unsafe fn dc_create_folder( let path = as_path(path);
context: &Context, let path_abs = dc_get_abs_path_safe(context, path);
pathNfilename: *const libc::c_char, if !path_abs.exists() {
) -> libc::c_int { match fs::create_dir_all(path_abs) {
let mut success = 0; Ok(_) => 1,
let pathNfilename_abs = dc_get_abs_path(context, pathNfilename); Err(_err) => {
{ warn!(
let p = std::path::Path::new(as_str(pathNfilename_abs)); context,
if !p.exists() { 0,
match fs::create_dir_all(p) { "Cannot create directory \"{}\".",
Ok(_) => { path.display(),
success = 1; );
} 0
Err(_err) => {
warn!(
context,
0,
"Cannot create directory \"{}\".",
as_str(pathNfilename),
);
}
} }
} else {
success = 1;
} }
} else {
1
} }
free(pathNfilename_abs as *mut libc::c_void);
success
} }
#[allow(non_snake_case)] #[allow(non_snake_case)]
@@ -1211,33 +1173,24 @@ pub unsafe fn dc_write_file(
dc_write_file_safe(context, as_str(pathNfilename), bytes) as libc::c_int dc_write_file_safe(context, as_str(pathNfilename), bytes) as libc::c_int
} }
#[allow(non_snake_case)] pub fn dc_write_file_safe<P: AsRef<std::path::Path>>(
pub fn dc_write_file_safe(context: &Context, pathNfilename: impl AsRef<str>, buf: &[u8]) -> bool { context: &Context,
let pathNfilename_abs = unsafe { path: P,
let n = CString::yolo(pathNfilename.as_ref()); buf: &[u8],
dc_get_abs_path(context, n.as_ptr()) ) -> bool {
}; let path_abs = dc_get_abs_path_safe(context, &path);
if pathNfilename_abs.is_null() { if let Err(_err) = fs::write(&path_abs, buf) {
return false;
}
let p = as_str(pathNfilename_abs);
let success = if let Err(_err) = fs::write(p, buf) {
warn!( warn!(
context, context,
0, 0,
"Cannot write {} bytes to \"{}\".", "Cannot write {} bytes to \"{}\".",
buf.len(), buf.len(),
pathNfilename.as_ref(), path.as_ref().display(),
); );
false false
} else { } else {
true true
}; }
unsafe { free(pathNfilename_abs as *mut libc::c_void) };
success
} }
#[allow(non_snake_case)] #[allow(non_snake_case)]
@@ -1260,34 +1213,20 @@ pub unsafe fn dc_read_file(
} }
} }
#[allow(non_snake_case)] pub fn dc_read_file_safe<P: AsRef<std::path::Path>>(context: &Context, path: P) -> Option<Vec<u8>> {
pub fn dc_read_file_safe(context: &Context, pathNfilename: impl AsRef<str>) -> Option<Vec<u8>> { let path_abs = dc_get_abs_path_safe(context, &path);
let pathNfilename_abs = unsafe { match fs::read(&path_abs) {
let n = CString::yolo(pathNfilename.as_ref());
dc_get_abs_path(context, n.as_ptr())
};
if pathNfilename_abs.is_null() {
return None;
}
let p = as_str(pathNfilename_abs);
let res = match fs::read(p) {
Ok(bytes) => Some(bytes), Ok(bytes) => Some(bytes),
Err(_err) => { Err(_err) => {
warn!( warn!(
context, context,
0, 0,
"Cannot read \"{}\" or file is empty.", "Cannot read \"{}\" or file is empty.",
pathNfilename.as_ref(), path.as_ref().display()
); );
None None
} }
}; }
unsafe { free(pathNfilename_abs as *mut libc::c_void) };
res
} }
#[allow(non_snake_case)] #[allow(non_snake_case)]

View File

@@ -1047,10 +1047,8 @@ pub fn housekeeping(context: &Context) {
unreferenced_count, unreferenced_count,
entry.file_name() entry.file_name()
); );
unsafe { let path = entry.path().to_c_string().unwrap();
let path = entry.path().to_c_string().unwrap(); dc_delete_file(context, path.as_ptr());
dc_delete_file(context, path.as_ptr());
}
} }
} }
Err(err) => { Err(err) => {