mirror of
https://github.com/chatmail/core.git
synced 2026-04-25 01:16:29 +03:00
refactor: safe sql access
This commit is contained in:
197
src/dc_tools.rs
197
src/dc_tools.rs
@@ -1,3 +1,4 @@
|
||||
use std::borrow::Cow;
|
||||
use std::fs;
|
||||
use std::time::SystemTime;
|
||||
|
||||
@@ -343,25 +344,13 @@ pub unsafe fn dc_utf8_strlen(s: *const libc::c_char) -> size_t {
|
||||
j
|
||||
}
|
||||
|
||||
pub unsafe fn dc_truncate_str(buf: *mut libc::c_char, approx_chars: libc::c_int) {
|
||||
if approx_chars > 0
|
||||
&& strlen(buf)
|
||||
> approx_chars.wrapping_add(
|
||||
strlen(b"[...]\x00" as *const u8 as *const libc::c_char) as libc::c_int
|
||||
) as usize
|
||||
{
|
||||
let mut p: *mut libc::c_char = &mut *buf.offset(approx_chars as isize) as *mut libc::c_char;
|
||||
*p = 0i32 as libc::c_char;
|
||||
if !strchr(buf, ' ' as i32).is_null() {
|
||||
while *p.offset(-1i32 as isize) as libc::c_int != ' ' as i32
|
||||
&& *p.offset(-1i32 as isize) as libc::c_int != '\n' as i32
|
||||
{
|
||||
p = p.offset(-1isize);
|
||||
*p = 0i32 as libc::c_char
|
||||
}
|
||||
}
|
||||
strcat(p, b"[...]\x00" as *const u8 as *const libc::c_char);
|
||||
};
|
||||
pub fn dc_truncate_str(buf: &str, approx_chars: usize) -> Cow<str> {
|
||||
let appendix = "[...]";
|
||||
if approx_chars > 0 && buf.len() > approx_chars + appendix.len() {
|
||||
Cow::Owned(format!("{}{}", &buf[..approx_chars], appendix))
|
||||
} else {
|
||||
Cow::Borrowed(buf)
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn dc_truncate_n_unwrap_str(
|
||||
@@ -675,12 +664,15 @@ pub unsafe fn dc_timestamp_from_date(date_time: *mut mailimf_date_time) -> i64 {
|
||||
|
||||
/* the return value must be free()'d */
|
||||
pub unsafe fn dc_timestamp_to_str(wanted: i64) -> *mut libc::c_char {
|
||||
let ts = chrono::Utc.timestamp(wanted, 0);
|
||||
let res = ts.format("%Y.%m.%d %H:%M:%S").to_string();
|
||||
|
||||
let res = dc_timestamp_to_str_safe(wanted);
|
||||
strdup(to_cstring(res).as_ptr())
|
||||
}
|
||||
|
||||
pub fn dc_timestamp_to_str_safe(wanted: i64) -> String {
|
||||
let ts = chrono::Utc.timestamp(wanted, 0);
|
||||
ts.format("%Y.%m.%d %H:%M:%S").to_string()
|
||||
}
|
||||
|
||||
pub fn dc_gm2local_offset() -> i64 {
|
||||
let lt = Local::now();
|
||||
((lt.offset().local_minus_utc() / (60 * 60)) * 100) as i64
|
||||
@@ -905,16 +897,23 @@ pub unsafe fn dc_extract_grpid_from_rfc724_mid_list(list: *const clist) -> *mut
|
||||
|
||||
/* file tools */
|
||||
pub unsafe fn dc_ensure_no_slash(pathNfilename: *mut libc::c_char) {
|
||||
let path_len: libc::c_int = strlen(pathNfilename) as libc::c_int;
|
||||
if path_len > 0i32 {
|
||||
if *pathNfilename.offset((path_len - 1i32) as isize) as libc::c_int == '/' as i32
|
||||
|| *pathNfilename.offset((path_len - 1i32) as isize) as libc::c_int == '\\' as i32
|
||||
let path_len = strlen(pathNfilename);
|
||||
if path_len > 0 {
|
||||
if *pathNfilename.offset((path_len - 1) as isize) as libc::c_int == '/' as i32
|
||||
|| *pathNfilename.offset((path_len - 1) as isize) as libc::c_int == '\\' as i32
|
||||
{
|
||||
*pathNfilename.offset((path_len - 1i32) as isize) = 0i32 as libc::c_char
|
||||
*pathNfilename.offset((path_len - 1) as isize) = 0 as libc::c_char
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub fn dc_ensure_no_slash_safe(path: &str) -> &str {
|
||||
if path.ends_with('/') || path.ends_with('\\') {
|
||||
return &path[..path.len() - 1];
|
||||
}
|
||||
path
|
||||
}
|
||||
|
||||
pub unsafe fn dc_validate_filename(filename: *mut libc::c_char) {
|
||||
/* function modifies the given buffer and replaces all characters not valid in filenames by a "-" */
|
||||
let mut p1: *mut libc::c_char = filename;
|
||||
@@ -1256,37 +1255,34 @@ pub unsafe fn dc_write_file(
|
||||
buf: *const libc::c_void,
|
||||
buf_bytes: size_t,
|
||||
) -> libc::c_int {
|
||||
let mut success = 0;
|
||||
let pathNfilename_abs = dc_get_abs_path(context, pathNfilename);
|
||||
|
||||
if pathNfilename_abs.is_null() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
let p = std::ffi::CStr::from_ptr(pathNfilename_abs)
|
||||
.to_str()
|
||||
.unwrap();
|
||||
|
||||
let bytes = std::slice::from_raw_parts(buf as *const u8, buf_bytes);
|
||||
|
||||
match fs::write(p, bytes) {
|
||||
Ok(_) => {
|
||||
info!(context, 0, "wrote file {}", as_str(pathNfilename));
|
||||
dc_write_file_safe(context, as_str(pathNfilename), bytes) as libc::c_int
|
||||
}
|
||||
|
||||
success = 1;
|
||||
}
|
||||
Err(_err) => {
|
||||
warn!(
|
||||
context,
|
||||
0,
|
||||
"Cannot write {} bytes to \"{}\".",
|
||||
buf_bytes,
|
||||
as_str(pathNfilename),
|
||||
);
|
||||
}
|
||||
pub fn dc_write_file_safe(context: &Context, pathNfilename: impl AsRef<str>, buf: &[u8]) -> bool {
|
||||
let pathNfilename_abs =
|
||||
unsafe { dc_get_abs_path(context, to_cstring(pathNfilename.as_ref()).as_ptr()) };
|
||||
if pathNfilename_abs.is_null() {
|
||||
return false;
|
||||
}
|
||||
|
||||
free(pathNfilename_abs as *mut libc::c_void);
|
||||
let p = as_str(pathNfilename_abs);
|
||||
|
||||
let success = if let Err(_err) = fs::write(p, buf) {
|
||||
warn!(
|
||||
context,
|
||||
0,
|
||||
"Cannot write {} bytes to \"{}\".",
|
||||
buf.len(),
|
||||
pathNfilename.as_ref(),
|
||||
);
|
||||
false
|
||||
} else {
|
||||
true
|
||||
};
|
||||
|
||||
unsafe { free(pathNfilename_abs as *mut libc::c_void) };
|
||||
success
|
||||
}
|
||||
|
||||
@@ -1296,44 +1292,43 @@ pub unsafe fn dc_read_file(
|
||||
buf: *mut *mut libc::c_void,
|
||||
buf_bytes: *mut size_t,
|
||||
) -> libc::c_int {
|
||||
let mut success = 0;
|
||||
|
||||
if pathNfilename.is_null() || buf.is_null() || buf_bytes.is_null() {
|
||||
if pathNfilename.is_null() {
|
||||
return 0;
|
||||
}
|
||||
if let Some(mut bytes) = dc_read_file_safe(context, as_str(pathNfilename)) {
|
||||
*buf = &mut bytes[..] as *mut _ as *mut libc::c_void;
|
||||
*buf_bytes = bytes.len();
|
||||
std::mem::forget(bytes);
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
*buf = 0 as *mut libc::c_void;
|
||||
*buf_bytes = 0i32 as size_t;
|
||||
|
||||
let pathNfilename_abs = dc_get_abs_path(context, pathNfilename);
|
||||
pub fn dc_read_file_safe(context: &Context, pathNfilename: impl AsRef<str>) -> Option<Vec<u8>> {
|
||||
let pathNfilename_abs =
|
||||
unsafe { dc_get_abs_path(context, to_cstring(pathNfilename.as_ref()).as_ptr()) };
|
||||
if pathNfilename_abs.is_null() {
|
||||
return 0;
|
||||
return None;
|
||||
}
|
||||
|
||||
let p = std::ffi::CStr::from_ptr(pathNfilename_abs)
|
||||
.to_str()
|
||||
.unwrap();
|
||||
|
||||
match fs::read(p) {
|
||||
Ok(mut bytes) => {
|
||||
*buf = &mut bytes[..] as *mut _ as *mut libc::c_void;
|
||||
*buf_bytes = bytes.len();
|
||||
std::mem::forget(bytes);
|
||||
|
||||
success = 1;
|
||||
}
|
||||
let p = as_str(pathNfilename_abs);
|
||||
let res = match fs::read(p) {
|
||||
Ok(bytes) => Some(bytes),
|
||||
Err(_err) => {
|
||||
dc_log_warning(
|
||||
warn!(
|
||||
context,
|
||||
0,
|
||||
b"Cannot read \"%s\" or file is empty.\x00" as *const u8 as *const libc::c_char,
|
||||
pathNfilename,
|
||||
"Cannot read \"{}\" or file is empty.",
|
||||
pathNfilename.as_ref(),
|
||||
);
|
||||
None
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
free(pathNfilename_abs as *mut libc::c_void);
|
||||
success
|
||||
unsafe { free(pathNfilename_abs as *mut libc::c_void) };
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
pub unsafe fn dc_get_fine_pathNfilename(
|
||||
@@ -1706,61 +1701,29 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_dc_str_truncate_1() {
|
||||
unsafe {
|
||||
let str: *mut libc::c_char =
|
||||
strdup(b"this is a little test string\x00" as *const u8 as *const libc::c_char);
|
||||
dc_truncate_str(str, 16);
|
||||
assert_eq!(
|
||||
CStr::from_ptr(str as *const libc::c_char).to_str().unwrap(),
|
||||
"this is a [...]"
|
||||
);
|
||||
free(str as *mut libc::c_void);
|
||||
}
|
||||
let s = "this is a little test string";
|
||||
assert_eq!(dc_truncate_str(s, 16), "this is a [...]");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dc_str_truncate_2() {
|
||||
unsafe {
|
||||
let str: *mut libc::c_char = strdup(b"1234\x00" as *const u8 as *const libc::c_char);
|
||||
dc_truncate_str(str, 2);
|
||||
assert_eq!(
|
||||
CStr::from_ptr(str as *const libc::c_char).to_str().unwrap(),
|
||||
"1234"
|
||||
);
|
||||
free(str as *mut libc::c_void);
|
||||
}
|
||||
assert_eq!(dc_truncate_str("1234", 2), "1234");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dc_str_truncate_3() {
|
||||
unsafe {
|
||||
let str: *mut libc::c_char = strdup(b"1234567\x00" as *const u8 as *const libc::c_char);
|
||||
dc_truncate_str(str, 1);
|
||||
assert_eq!(
|
||||
CStr::from_ptr(str as *const libc::c_char).to_str().unwrap(),
|
||||
"1[...]"
|
||||
);
|
||||
free(str as *mut libc::c_void);
|
||||
}
|
||||
assert_eq!(dc_truncate_str("1234567", 3), "1[...]");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dc_str_truncate_4() {
|
||||
unsafe {
|
||||
let str: *mut libc::c_char = strdup(b"123456\x00" as *const u8 as *const libc::c_char);
|
||||
dc_truncate_str(str, 4);
|
||||
assert_eq!(
|
||||
CStr::from_ptr(str as *const libc::c_char).to_str().unwrap(),
|
||||
"123456"
|
||||
);
|
||||
free(str as *mut libc::c_void);
|
||||
}
|
||||
assert_eq!(dc_truncate_str("123456", 4), "123456");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dc_insert_breaks_1() {
|
||||
unsafe {
|
||||
let str: *mut libc::c_char = dc_insert_breaks(
|
||||
let str = dc_insert_breaks(
|
||||
b"just1234test\x00" as *const u8 as *const libc::c_char,
|
||||
4,
|
||||
b" \x00" as *const u8 as *const libc::c_char,
|
||||
|
||||
Reference in New Issue
Block a user