The big sqlite refactor

* refactor: safe sql access

* Clean up the worst rebase mistakes

* Some more progress on the rebase fallout and this branch

* upgrade and compile again

* cleanup from rebase

* example of how to prepare now

* rebase fixes

* add sql.query_map

* less preparation

* more improvements in sql code

* fix string truncation

* more prepare conversions

* most prep done

* fix tests

* fix ffi

* fix last prepares

* fix segfaults and some queries

* use r2d2 pool

* fix dc_job sql call, to reduce contention

* try newer rust

* No more vararg printing (drop dc_log_)

* ignore expected errors

* fix: uses exists instead of execute where needed

* fix: get_contacts logic was broken

* fix: contact creation

* test on 32bit linux

* ci: try running 32bit without cross

* undo 32bit tests

* refactor: rename dc_sqlite3 to sql

* fix: safer string conversions

* more string fixes

* try fixing appveyor build to 64bit

* chore(ci): hardcode target

* chore(ci): appveyor

* some cleanup work

* try fix darwin

* fix and improve sql escaping

* fix various bugs

* fix chat deletion

* refactor: cleanup config values and move to their own file

* refactor: move more methods onto the sql struct

* dont panic on failed state loading

* first round of cr

* one more cr fix

* stop using strange defaults

* remove unused escapes
This commit is contained in:
Friedel Ziegelmayer
2019-07-18 00:24:45 +02:00
committed by GitHub
parent 3e3403d3d7
commit 8a0fc609e6
47 changed files with 7356 additions and 9608 deletions

View File

@@ -1,3 +1,4 @@
use std::borrow::Cow;
use std::fs;
use std::time::SystemTime;
@@ -7,10 +8,11 @@ use rand::{thread_rng, Rng};
use crate::context::Context;
use crate::dc_array::*;
use crate::dc_log::*;
use crate::types::*;
use crate::x::*;
const ELLIPSE: &'static str = "[...]";
/* Some tools and enhancements to the used libraries, there should be
no references to Context and other "larger" classes here. */
// for carray etc.
@@ -343,25 +345,16 @@ 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
}
pub fn dc_truncate_str(buf: &str, approx_chars: usize) -> Cow<str> {
if approx_chars > 0 && buf.len() > approx_chars + ELLIPSE.len() {
if let Some(index) = buf[..approx_chars].rfind(|c| c == ' ' || c == '\n') {
Cow::Owned(format!("{}{}", &buf[..index + 1], ELLIPSE))
} else {
Cow::Owned(format!("{}{}", &buf[..approx_chars], ELLIPSE))
}
strcat(p, b"[...]\x00" as *const u8 as *const libc::c_char);
};
} else {
Cow::Borrowed(buf)
}
}
pub unsafe fn dc_truncate_n_unwrap_str(
@@ -675,12 +668,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 +901,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;
@@ -1169,12 +1172,7 @@ pub unsafe fn dc_delete_file(context: &Context, pathNfilename: *const libc::c_ch
success = 1;
}
Err(_err) => {
dc_log_warning(
context,
0i32,
b"Cannot delete \"%s\".\x00" as *const u8 as *const libc::c_char,
pathNfilename,
);
warn!(context, 0, "Cannot delete \"{}\".", as_str(pathNfilename),);
}
}
@@ -1204,13 +1202,7 @@ pub unsafe fn dc_copy_file(
success = 1;
}
Err(_) => {
dc_log_error(
context,
0,
b"Cannot copy \"%s\" to \"%s\".\x00" as *const u8 as *const libc::c_char,
src,
dest,
);
error!(context, 0, "Cannot copy \"{}\" to \"{}\".", src_p, dest_p,);
}
}
@@ -1233,11 +1225,11 @@ pub unsafe fn dc_create_folder(
success = 1;
}
Err(_err) => {
dc_log_warning(
warn!(
context,
0i32,
b"Cannot create directory \"%s\".\x00" as *const u8 as *const libc::c_char,
pathNfilename,
0,
"Cannot create directory \"{}\".",
as_str(pathNfilename),
);
}
}
@@ -1256,37 +1248,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 +1285,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 +1694,30 @@ 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);
}
}
// This test seems wrong
// #[test]
// fn test_dc_str_truncate_3() {
// 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,