diff --git a/src/dc_imex.rs b/src/dc_imex.rs index a2dc5df0e..6cebf983d 100644 --- a/src/dc_imex.rs +++ b/src/dc_imex.rs @@ -101,7 +101,6 @@ pub unsafe fn dc_imex_has_backup( } pub unsafe fn dc_initiate_key_transfer(context: &Context) -> *mut libc::c_char { - let mut setup_file_name: *mut libc::c_char = ptr::null_mut(); let mut msg: Message; if !dc_alloc_ongoing(context) { return std::ptr::null_mut(); @@ -115,8 +114,7 @@ pub unsafe fn dc_initiate_key_transfer(context: &Context) -> *mut libc::c_char { .unwrap() .shall_stop_ongoing { - if let Ok(setup_file_content) = dc_render_setup_file(context, &setup_code) { - let setup_file_content_c = CString::yolo(setup_file_content.as_str()); + if let Ok(ref setup_file_content) = dc_render_setup_file(context, &setup_code) { /* encrypting may also take a while ... */ if !context .running_state @@ -125,23 +123,14 @@ pub unsafe fn dc_initiate_key_transfer(context: &Context) -> *mut libc::c_char { .unwrap() .shall_stop_ongoing { - setup_file_name = dc_get_fine_pathNfilename( - context, - b"$BLOBDIR\x00" as *const u8 as *const libc::c_char, - b"autocrypt-setup-message.html\x00" as *const u8 as *const libc::c_char, - ); - if !(setup_file_name.is_null() - || 0 == dc_write_file( - context, - setup_file_name, - setup_file_content_c.as_ptr() as *const libc::c_void, - setup_file_content_c.as_bytes().len(), - )) - { + let setup_file_name = + dc_get_fine_path_filename(context, "$BLOBDIR", "autocrypt-setup-message.html"); + if dc_write_file(context, &setup_file_name, setup_file_content.as_bytes()) { if let Ok(chat_id) = chat::create_by_contact_id(context, 1) { msg = dc_msg_new_untyped(); msg.type_0 = Viewtype::File; - msg.param.set(Param::File, as_str(setup_file_name)); + msg.param + .set(Param::File, setup_file_name.to_string_lossy()); msg.param .set(Param::MimeType, "application/autocrypt-setup"); @@ -182,7 +171,6 @@ pub unsafe fn dc_initiate_key_transfer(context: &Context) -> *mut libc::c_char { } } } - free(setup_file_name as *mut libc::c_void); dc_free_ongoing(context); setup_code.strdup() @@ -640,7 +628,7 @@ unsafe fn import_backup(context: &Context, backup_to_import: *const libc::c_char } let pathNfilename = context.get_blobdir().join(file_name); - if dc_write_file_safe(context, &pathNfilename, &file_blob) { + if dc_write_file(context, &pathNfilename, &file_blob) { continue; } error!( @@ -687,13 +675,8 @@ unsafe fn export_backup(context: &Context, dir: *const libc::c_char) -> bool { let res = chrono::NaiveDateTime::from_timestamp(now as i64, 0) .format("delta-chat-%Y-%m-%d.bak") .to_string(); - let buffer = CString::yolo(res); - let dest_pathNfilename = dc_get_fine_pathNfilename(context, dir, buffer.as_ptr()); - if dest_pathNfilename.is_null() { - error!(context, "Cannot get backup file name.",); - return success; - } + let dest_path_filename = dc_get_fine_path_filename(context, as_path(dir), res); sql::housekeeping(context); @@ -704,15 +687,15 @@ unsafe fn export_backup(context: &Context, dir: *const libc::c_char) -> bool { context, "Backup \"{}\" to \"{}\".", context.get_dbfile().display(), - as_str(dest_pathNfilename), + dest_path_filename.display(), ); - if dc_copy_file(context, context.get_dbfile(), as_path(dest_pathNfilename)) { + if dc_copy_file(context, context.get_dbfile(), &dest_path_filename) { context.sql.open(&context, &context.get_dbfile(), 0); closed = false; /* add all files as blobs to the database copy (this does not require the source to be locked, neigher the destination as it is used only here) */ /*for logging only*/ let sql = Sql::new(); - if sql.open(context, as_path(dest_pathNfilename), 0) { + if sql.open(context, &dest_path_filename, 0) { if !sql.table_exists("backup_blobs") { if sql::execute( context, @@ -821,9 +804,7 @@ unsafe fn export_backup(context: &Context, dir: *const libc::c_char) -> bool { .set_config_int(context, "backup_time", now as i32) .is_ok() { - context.call_cb(Event::ImexFileWritten( - as_path(dest_pathNfilename).to_path_buf(), - )); + context.call_cb(Event::ImexFileWritten(&dest_path_filename)); success = true; } } @@ -841,9 +822,8 @@ unsafe fn export_backup(context: &Context, dir: *const libc::c_char) -> bool { context.sql.open(&context, &context.get_dbfile(), 0); } if 0 != delete_dest_file { - dc_delete_file(context, as_path(dest_pathNfilename)); + dc_delete_file(context, &dest_path_filename); } - free(dest_pathNfilename as *mut libc::c_void); success } diff --git a/src/dc_mimeparser.rs b/src/dc_mimeparser.rs index 02aed946d..b26c56562 100644 --- a/src/dc_mimeparser.rs +++ b/src/dc_mimeparser.rs @@ -1301,44 +1301,30 @@ unsafe fn do_add_single_file_part( decoded_data_bytes: libc::size_t, desired_filename: *const libc::c_char, ) { - let pathNfilename: *mut libc::c_char; - /* create a free file name to use */ - pathNfilename = dc_get_fine_pathNfilename( - (*parser).context, - b"$BLOBDIR\x00" as *const u8 as *const libc::c_char, - desired_filename, - ); - if !pathNfilename.is_null() { - /* copy data to file */ - if !(dc_write_file( - (*parser).context, - pathNfilename, - decoded_data as *const libc::c_void, - decoded_data_bytes, - ) == 0i32) - { - let mut part = dc_mimepart_new(); - part.type_0 = msg_type; - part.int_mimetype = mime_type; - part.bytes = decoded_data_bytes as libc::c_int; - part.param.set(Param::File, as_str(pathNfilename)); - part.param.set(Param::MimeType, raw_mime); - if mime_type == 80 { - assert!(!decoded_data.is_null(), "invalid image data"); - let data = std::slice::from_raw_parts( - decoded_data as *const u8, - decoded_data_bytes as usize, - ); + let path_filename = + dc_get_fine_path_filename((*parser).context, "$BLOBDIR", as_str(desired_filename)); + let bytes = std::slice::from_raw_parts(decoded_data as *const u8, decoded_data_bytes); - if let Ok((width, height)) = dc_get_filemeta(data) { - part.param.set_int(Param::Width, width as i32); - part.param.set_int(Param::Height, height as i32); - } + /* copy data to file */ + if dc_write_file((*parser).context, &path_filename, bytes) { + let mut part = dc_mimepart_new(); + part.type_0 = msg_type; + part.int_mimetype = mime_type; + part.bytes = decoded_data_bytes as libc::c_int; + part.param.set(Param::File, path_filename.to_string_lossy()); + part.param.set(Param::MimeType, raw_mime); + if mime_type == 80 { + assert!(!decoded_data.is_null(), "invalid image data"); + let data = + std::slice::from_raw_parts(decoded_data as *const u8, decoded_data_bytes as usize); + + if let Ok((width, height)) = dc_get_filemeta(data) { + part.param.set_int(Param::Width, width as i32); + part.param.set_int(Param::Height, height as i32); } - do_add_single_part(parser, part); } + do_add_single_part(parser, part); } - free(pathNfilename as *mut libc::c_void); } unsafe fn do_add_single_part(parser: &mut dc_mimeparser_t, mut part: dc_mimepart_t) { diff --git a/src/dc_tools.rs b/src/dc_tools.rs index cb8c6d6b6..1ae3bfe73 100644 --- a/src/dc_tools.rs +++ b/src/dc_tools.rs @@ -1,12 +1,14 @@ +//! Some tools and enhancements to the used libraries, there should be +//! no references to Context and other "larger" entities here. + use std::borrow::Cow; -use std::ffi::{CStr, CString}; -use std::path::Path; +use std::ffi::{CStr, CString, OsString}; +use std::path::{Path, PathBuf}; use std::str::FromStr; use std::time::SystemTime; use std::{fmt, fs, ptr}; use chrono::{Local, TimeZone}; -use itertools::max; use libc::uintptr_t; use mmime::clist::*; use mmime::mailimf_types::*; @@ -16,10 +18,6 @@ use crate::context::Context; use crate::error::Error; use crate::x::*; -/* Some tools and enhancements to the used libraries, there should be -no references to Context and other "larger" classes here. */ -/* ** library-private **********************************************************/ -/* math tools */ pub fn dc_exactly_one_bit_set(v: libc::c_int) -> bool { 0 != v && 0 == v & (v - 1) } @@ -570,7 +568,7 @@ fn encode_66bits_as_base64(v1: u32, v2: u32, fill: u32) -> String { String::from_utf8(wrapped_writer).unwrap() } -pub unsafe fn dc_create_incoming_rfc724_mid( +pub fn dc_create_incoming_rfc724_mid( message_timestamp: i64, contact_id_from: u32, contact_ids_to: &Vec, @@ -579,51 +577,36 @@ pub unsafe fn dc_create_incoming_rfc724_mid( return ptr::null_mut(); } /* find out the largest receiver ID (we could also take the smallest, but it should be unique) */ - let largest_id_to = max(contact_ids_to.iter()); + let largest_id_to = contact_ids_to.iter().max().copied().unwrap_or_default(); - dc_mprintf( - b"%lu-%lu-%lu@stub\x00" as *const u8 as *const libc::c_char, - message_timestamp as libc::c_ulong, - contact_id_from as libc::c_ulong, - *largest_id_to.unwrap() as libc::c_ulong, - ) + let result = format!( + "{}-{}-{}@stub", + message_timestamp, contact_id_from, largest_id_to + ); + + unsafe { result.strdup() } } +/// Function generates a Message-ID that can be used for a new outgoing message. +/// - this function is called for all outgoing messages. +/// - the message ID should be globally unique +/// - do not add a counter or any private data as as this may give unneeded information to the receiver pub unsafe fn dc_create_outgoing_rfc724_mid( grpid: *const libc::c_char, from_addr: *const libc::c_char, ) -> *mut libc::c_char { - /* Function generates a Message-ID that can be used for a new outgoing message. - - this function is called for all outgoing messages. - - the message ID should be globally unique - - do not add a counter or any private data as as this may give unneeded information to the receiver */ - let mut rand1: *mut libc::c_char = ptr::null_mut(); - let rand2: *mut libc::c_char = dc_create_id().strdup(); - let ret: *mut libc::c_char; - let mut at_hostname: *const libc::c_char = strchr(from_addr, '@' as i32); - if at_hostname.is_null() { - at_hostname = b"@nohost\x00" as *const u8 as *const libc::c_char - } - if !grpid.is_null() { - ret = dc_mprintf( - b"Gr.%s.%s%s\x00" as *const u8 as *const libc::c_char, - grpid, - rand2, - at_hostname, - ) - } else { - rand1 = dc_create_id().strdup(); - ret = dc_mprintf( - b"Mr.%s.%s%s\x00" as *const u8 as *const libc::c_char, - rand1, - rand2, - at_hostname, - ) - } - free(rand1 as *mut libc::c_void); - free(rand2 as *mut libc::c_void); + let rand2 = dc_create_id(); - ret + let at_hostname = as_opt_str(strchr(from_addr, '@' as i32)).unwrap_or_else(|| "@nohost"); + + let ret = if !grpid.is_null() { + format!("Gr.{}.{}{}", as_str(grpid), rand2, at_hostname,) + } else { + let rand1 = dc_create_id(); + format!("Mr.{}.{}{}", rand1, rand2, at_hostname) + }; + + ret.strdup() } /// Generate globally-unique message-id for a new outgoing message. @@ -696,16 +679,6 @@ pub unsafe fn dc_extract_grpid_from_rfc724_mid_list(list: *const clist) -> *mut ptr::null_mut() } -#[allow(non_snake_case)] -unsafe fn dc_ensure_no_slash(pathNfilename: *mut libc::c_char) { - let path_len = strlen(pathNfilename); - if path_len > 0 && *pathNfilename.add(path_len - 1) as libc::c_int == '/' as i32 - || *pathNfilename.add(path_len - 1) as libc::c_int == '\\' as i32 - { - *pathNfilename.add(path_len - 1) = 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]; @@ -713,18 +686,12 @@ pub fn dc_ensure_no_slash_safe(path: &str) -> &str { path } -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; - while 0 != *p1 { - if *p1 as libc::c_int == '/' as i32 - || *p1 as libc::c_int == '\\' as i32 - || *p1 as libc::c_int == ':' as i32 - { - *p1 = '-' as i32 as libc::c_char - } - p1 = p1.offset(1isize) - } +/// Function modifies the given buffer and replaces all characters not valid in filenames by a "-". +fn validate_filename(filename: &str) -> String { + filename + .replace('/', "-") + .replace('\\', "-") + .replace(':', "-") } pub unsafe fn dc_get_filename(path_filename: impl AsRef) -> *mut libc::c_char { @@ -735,42 +702,6 @@ pub unsafe fn dc_get_filename(path_filename: impl AsRef) -> *mut libc::c_ch } } -// the case of the suffix is preserved -#[allow(non_snake_case)] -unsafe fn dc_split_filename( - pathNfilename: *const libc::c_char, - ret_basename: *mut *mut libc::c_char, - ret_all_suffixes_incl_dot: *mut *mut libc::c_char, -) { - if pathNfilename.is_null() { - return; - } - /* splits a filename into basename and all suffixes, eg. "/path/foo.tar.gz" is split into "foo.tar" and ".gz", - (we use the _last_ dot which allows the usage inside the filename which are very usual; - maybe the detection could be more intelligent, however, for the moment, it is just file) - - if there is no suffix, the returned suffix string is empty, eg. "/path/foobar" is split into "foobar" and "" - - the case of the returned suffix is preserved; this is to allow reconstruction of (similar) names */ - let basename: *mut libc::c_char = dc_get_filename(as_str(pathNfilename)); - let suffix: *mut libc::c_char; - let p1: *mut libc::c_char = strrchr(basename, '.' as i32); - if !p1.is_null() { - suffix = dc_strdup(p1); - *p1 = 0 as libc::c_char - } else { - suffix = dc_strdup(ptr::null()) - } - if !ret_basename.is_null() { - *ret_basename = basename - } else { - free(basename as *mut libc::c_void); - } - if !ret_all_suffixes_incl_dot.is_null() { - *ret_all_suffixes_incl_dot = suffix - } else { - free(suffix as *mut libc::c_void); - }; -} - // the returned suffix is lower-case #[allow(non_snake_case)] pub unsafe fn dc_get_filesuffix_lc(path_filename: impl AsRef) -> *mut libc::c_char { @@ -876,23 +807,8 @@ pub fn dc_create_folder(context: &Context, path: impl AsRef) -> } } -#[allow(non_snake_case)] -pub unsafe fn dc_write_file( - context: &Context, - pathNfilename: *const libc::c_char, - buf: *const libc::c_void, - buf_bytes: libc::size_t, -) -> libc::c_int { - let bytes = std::slice::from_raw_parts(buf as *const u8, buf_bytes); - - dc_write_file_safe(context, as_str(pathNfilename), bytes) as libc::c_int -} - -pub fn dc_write_file_safe>( - context: &Context, - path: P, - buf: &[u8], -) -> bool { +/// Write a the given content to provied file path. +pub fn dc_write_file(context: &Context, path: impl AsRef, buf: &[u8]) -> bool { let path_abs = dc_get_abs_path(context, &path); if let Err(_err) = fs::write(&path_abs, buf) { warn!( @@ -942,58 +858,48 @@ pub fn dc_read_file_safe>(context: &Context, path: P) } } -#[allow(non_snake_case)] -pub unsafe fn dc_get_fine_pathNfilename( +pub fn dc_get_fine_path_filename( context: &Context, - pathNfolder: *const libc::c_char, - desired_filenameNsuffix__: *const libc::c_char, -) -> *mut libc::c_char { - let mut ret: *mut libc::c_char = ptr::null_mut(); - let pathNfolder_wo_slash: *mut libc::c_char; - let filenameNsuffix: *mut libc::c_char; - let mut basename: *mut libc::c_char = ptr::null_mut(); - let mut dotNSuffix: *mut libc::c_char = ptr::null_mut(); + folder: impl AsRef, + desired_filename_suffix: impl AsRef, +) -> PathBuf { let now = time(); - pathNfolder_wo_slash = dc_strdup(pathNfolder); - dc_ensure_no_slash(pathNfolder_wo_slash); - filenameNsuffix = dc_strdup(desired_filenameNsuffix__); - dc_validate_filename(filenameNsuffix); - dc_split_filename(filenameNsuffix, &mut basename, &mut dotNSuffix); + let folder = PathBuf::from(folder.as_ref()); + let suffix = validate_filename(desired_filename_suffix.as_ref()); - for i in 0..1000i64 { - /*no deadlocks, please*/ - if 0 != i { - let idx = if i < 100 { i } else { now + i }; - ret = dc_mprintf( - b"%s/%s-%lu%s\x00" as *const u8 as *const libc::c_char, - pathNfolder_wo_slash, - basename, - idx as libc::c_ulong, - dotNSuffix, - ) + let file_name = PathBuf::from(suffix); + let extension = file_name.extension().map(|c| c.clone()); + + for i in 0..100_000 { + let ret = if i == 0 { + let mut folder = folder.clone(); + folder.push(&file_name); + folder } else { - ret = dc_mprintf( - b"%s/%s%s\x00" as *const u8 as *const libc::c_char, - pathNfolder_wo_slash, - basename, - dotNSuffix, - ) + let idx = if i < 100 { i } else { now + i }; + let file_name = if let Some(stem) = file_name.file_stem() { + let mut stem = stem.to_os_string(); + stem.push(format!("-{}", idx)); + stem + } else { + OsString::from(idx.to_string()) + }; + let mut folder = folder.clone(); + folder.push(file_name); + if let Some(ext) = extension { + folder.set_extension(&ext); + } + folder + }; + + if !dc_file_exist(context, &ret) { + // fine filename found + return ret; } - if !dc_file_exist(context, as_path(ret)) { - /* fine filename found */ - break; - } - free(ret as *mut libc::c_void); - ret = ptr::null_mut(); } - free(filenameNsuffix as *mut libc::c_void); - free(basename as *mut libc::c_void); - free(dotNSuffix as *mut libc::c_void); - free(pathNfolder_wo_slash as *mut libc::c_void); - - ret + panic!("Something is really wrong, you need to clean up your disk"); } pub fn dc_is_blobdir_path(context: &Context, path: impl AsRef) -> bool { @@ -1017,38 +923,18 @@ fn dc_make_rel_path(context: &Context, path: &mut String) { } pub fn dc_make_rel_and_copy(context: &Context, path: &mut String) -> bool { - let mut success = false; - let mut filename = ptr::null_mut(); - let mut blobdir_path = ptr::null_mut(); if dc_is_blobdir_path(context, &path) { dc_make_rel_path(context, path); - success = true; - } else { - filename = unsafe { dc_get_filename(&path) }; - if !(filename.is_null() - || { - blobdir_path = unsafe { - dc_get_fine_pathNfilename( - context, - b"$BLOBDIR\x00" as *const u8 as *const libc::c_char, - filename, - ) - }; - blobdir_path.is_null() - } - || !dc_copy_file(context, &path, as_path(blobdir_path))) - { - *path = to_string(blobdir_path); - blobdir_path = ptr::null_mut(); - dc_make_rel_path(context, path); - success = true; - } + return true; } - unsafe { - free(blobdir_path.cast()); - free(filename.cast()); + let blobdir_path = dc_get_fine_path_filename(context, "$BLOBDIR", &path); + if dc_copy_file(context, &path, &blobdir_path) { + *path = blobdir_path.to_string_lossy().to_string(); + dc_make_rel_path(context, path); + return true; } - success + + false } /// Error type for the [OsStrExt] trait @@ -1923,4 +1809,14 @@ mod tests { } } } + + #[test] + fn test_dc_create_incoming_rfc724_mid() { + let res = dc_create_incoming_rfc724_mid(123, 45, &vec![6, 7]); + assert_eq!(as_str(res), "123-45-7@stub"); + + unsafe { + free(res.cast()); + } + } } diff --git a/src/job.rs b/src/job.rs index 43fb07957..d9a79a615 100644 --- a/src/job.rs +++ b/src/job.rs @@ -998,38 +998,23 @@ fn send_mdn(context: &Context, msg_id: u32) { #[allow(non_snake_case)] fn add_smtp_job(context: &Context, action: Action, mimefactory: &dc_mimefactory_t) -> libc::c_int { - let pathNfilename: *mut libc::c_char; let mut success: libc::c_int = 0i32; let mut recipients: *mut libc::c_char = ptr::null_mut(); let mut param = Params::new(); - pathNfilename = unsafe { - dc_get_fine_pathNfilename( - context, - b"$BLOBDIR\x00" as *const u8 as *const libc::c_char, - mimefactory.rfc724_mid, + let path_filename = + dc_get_fine_path_filename(context, "$BLOBDIR", as_str(mimefactory.rfc724_mid)); + let bytes = unsafe { + std::slice::from_raw_parts( + (*mimefactory.out).str_0 as *const u8, + (*mimefactory.out).len, ) }; - if pathNfilename.is_null() { - error!( - context, - "Could not find free file name for message with ID <{}>.", - to_string(mimefactory.rfc724_mid), - ); - } else if 0 - == unsafe { - dc_write_file( - context, - pathNfilename, - (*mimefactory.out).str_0 as *const libc::c_void, - (*mimefactory.out).len, - ) - } - { + if !dc_write_file(context, &path_filename, bytes) { error!( context, "Could not write message <{}> to \"{}\".", to_string(mimefactory.rfc724_mid), - as_str(pathNfilename), + path_filename.display(), ); } else { recipients = unsafe { @@ -1038,7 +1023,7 @@ fn add_smtp_job(context: &Context, action: Action, mimefactory: &dc_mimefactory_ b"\x1e\x00" as *const u8 as *const libc::c_char, ) }; - param.set(Param::File, as_str(pathNfilename)); + param.set(Param::File, path_filename.to_string_lossy()); param.set(Param::Recipients, as_str(recipients)); job_add( context, @@ -1057,7 +1042,6 @@ fn add_smtp_job(context: &Context, action: Action, mimefactory: &dc_mimefactory_ } unsafe { free(recipients.cast()); - free(pathNfilename.cast()); } success } diff --git a/src/key.rs b/src/key.rs index 9afc8ff43..c7193cbd7 100644 --- a/src/key.rs +++ b/src/key.rs @@ -218,7 +218,7 @@ impl Key { pub fn write_asc_to_file(&self, file: impl AsRef, context: &Context) -> bool { let file_content = self.to_asc(None).into_bytes(); - if dc_write_file_safe(context, &file, &file_content) { + if dc_write_file(context, &file, &file_content) { return true; } else { error!(context, "Cannot write key to {}", file.as_ref().display()); diff --git a/tests/stress.rs b/tests/stress.rs index f94e97091..544fde8b5 100644 --- a/tests/stress.rs +++ b/tests/stress.rs @@ -1,6 +1,7 @@ //! Stress some functions for testing; if used as a lib, this file is obsolete. use std::collections::HashSet; +use std::path::PathBuf; use std::ptr; use tempfile::{tempdir, TempDir}; @@ -39,15 +40,10 @@ unsafe fn stress_functions(context: &Context) { dc_delete_file(context, "$BLOBDIR/foobar.dadada"); dc_delete_file(context, "$BLOBDIR/foobar-folder"); } - dc_write_file( - context, - b"$BLOBDIR/foobar\x00" as *const u8 as *const libc::c_char, - b"content\x00" as *const u8 as *const libc::c_char as *const libc::c_void, - 7, - ); + assert!(dc_write_file(context, "$BLOBDIR/foobar", b"content")); assert!(dc_file_exist(context, "$BLOBDIR/foobar",)); assert!(!dc_file_exist(context, "$BLOBDIR/foobarx")); - assert_eq!(dc_get_filebytes(context, "$BLOBDIR/foobar",), 7); + assert_eq!(dc_get_filebytes(context, "$BLOBDIR/foobar"), 7); let abs_path = context .get_blobdir() @@ -87,41 +83,14 @@ unsafe fn stress_functions(context: &Context) { assert!(dc_create_folder(context, "$BLOBDIR/foobar-folder")); assert!(dc_file_exist(context, "$BLOBDIR/foobar-folder",)); assert!(!dc_delete_file(context, "$BLOBDIR/foobar-folder")); - let fn0: *mut libc::c_char = dc_get_fine_pathNfilename( - context, - b"$BLOBDIR\x00" as *const u8 as *const libc::c_char, - b"foobar.dadada\x00" as *const u8 as *const libc::c_char, - ); - assert!(!fn0.is_null()); - assert_eq!( - strcmp( - fn0, - b"$BLOBDIR/foobar.dadada\x00" as *const u8 as *const libc::c_char, - ), - 0 - ); - dc_write_file( - context, - fn0, - b"content\x00" as *const u8 as *const libc::c_char as *const libc::c_void, - 7, - ); - let fn1: *mut libc::c_char = dc_get_fine_pathNfilename( - context, - b"$BLOBDIR\x00" as *const u8 as *const libc::c_char, - b"foobar.dadada\x00" as *const u8 as *const libc::c_char, - ); - assert!(!fn1.is_null()); - assert_eq!( - strcmp( - fn1, - b"$BLOBDIR/foobar-1.dadada\x00" as *const u8 as *const libc::c_char, - ), - 0 - ); - assert!(dc_delete_file(context, as_path(fn0))); - free(fn0 as *mut libc::c_void); - free(fn1 as *mut libc::c_void); + let fn0 = dc_get_fine_path_filename(context, "$BLOBDIR", "foobar.dadada"); + assert_eq!(fn0, PathBuf::from("$BLOBDIR/foobar.dadada")); + + assert!(dc_write_file(context, &fn0, b"content")); + let fn1 = dc_get_fine_path_filename(context, "$BLOBDIR", "foobar.dadada"); + assert_eq!(fn1, PathBuf::from("$BLOBDIR/foobar-1.dadada")); + + assert!(dc_delete_file(context, &fn0)); let res = context.get_config(config::Config::SysConfigKeys).unwrap();