From 3e72cf37a96562f5c9000f2761da7d866ce35fd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Michaj=C5=82ow?= Date: Fri, 21 Feb 2025 19:57:27 +0100 Subject: [PATCH] misc/io_utils.rs: add rust impl of atomic file save --- meson.build | 15 ++++- misc/io_utils.c | 29 --------- misc/io_utils.rs | 61 +++++++++++++++++++ player/lua/osc.lua | 8 ++- player/lua/stats.lua | 3 +- subprojects/cfg_if.wrap | 6 ++ subprojects/critical_section.wrap | 6 ++ subprojects/fastrand.wrap | 6 ++ subprojects/once_cell.wrap | 6 ++ subprojects/packagefiles/cfg_if/meson.build | 18 ++++++ subprojects/packagefiles/fastrand/meson.build | 24 ++++++++ .../packagefiles/once_cell/meson.build | 23 +++++++ subprojects/packagefiles/tempfile/meson.build | 39 ++++++++++++ .../packagefiles/windows_sys/meson.build | 29 +++++++++ .../packagefiles/windows_targets/meson.build | 18 ++++++ subprojects/portable_atomic.wrap | 6 ++ subprojects/tempfile.wrap | 6 ++ subprojects/windows_sys.wrap | 6 ++ subprojects/windows_targets.wrap | 6 ++ 19 files changed, 279 insertions(+), 36 deletions(-) create mode 100644 misc/io_utils.rs create mode 100644 subprojects/cfg_if.wrap create mode 100644 subprojects/critical_section.wrap create mode 100644 subprojects/fastrand.wrap create mode 100644 subprojects/once_cell.wrap create mode 100644 subprojects/packagefiles/cfg_if/meson.build create mode 100644 subprojects/packagefiles/fastrand/meson.build create mode 100644 subprojects/packagefiles/once_cell/meson.build create mode 100644 subprojects/packagefiles/tempfile/meson.build create mode 100644 subprojects/packagefiles/windows_sys/meson.build create mode 100644 subprojects/packagefiles/windows_targets/meson.build create mode 100644 subprojects/portable_atomic.wrap create mode 100644 subprojects/tempfile.wrap create mode 100644 subprojects/windows_sys.wrap create mode 100644 subprojects/windows_targets.wrap diff --git a/meson.build b/meson.build index 06324ef1a8022..73a2de7e752dc 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('mpv', - 'c', + ['c', 'rust'], license: ['GPL2+', 'LGPL2.1+'], version: files('./MPV_VERSION'), meson_version: '>=1.3.0', @@ -11,6 +11,8 @@ project('mpv', 'cpp_std=c++20', 'cpp_eh=default', 'warning_level=2', + 'rust_std=2021', + 'build.rust_std=2021', ] ) @@ -1761,6 +1763,13 @@ major = client_h_define.split('|')[0].split('<<')[0].strip('() ') minor = client_h_define.split('|')[1].strip('() ') client_api_version = major + '.' + minor + '.0' +tempfile_dep = dependency('tempfile', fallback : ['tempfile', 'tempfile_dep']) +libmpv_rs = static_library('libmpv_rs', + 'misc/io_utils.rs', + rust_abi: 'c', + dependencies: tempfile_dep +) + libmpv = library('mpv', sources, dependencies: dependencies, gnu_symbol_visibility: 'hidden', link_args: cc.get_supported_link_arguments(['-Wl,-Bsymbolic']), version: client_api_version, install: get_option('libmpv'), @@ -1777,7 +1786,7 @@ if get_option('libmpv') install_headers(headers, subdir: 'mpv') # Allow projects to build with libmpv by cloning into ./subprojects/mpv - libmpv_dep = declare_dependency(link_with: libmpv) + libmpv_dep = declare_dependency(link_with: [libmpv, libmpv_rs]) meson.override_dependency('mpv', libmpv_dep) endif @@ -1810,7 +1819,7 @@ if get_option('cplayer') install_data('etc/mpv-symbolic.svg', install_dir: join_paths(hicolor_dir, 'symbolic', 'apps')) mpv = executable('mpv', main_fn_source, objects: libmpv.extract_all_objects(recursive: true), dependencies: dependencies, - win_subsystem: get_option('win32-subsystem'), install: true) + link_with: libmpv_rs, win_subsystem: get_option('win32-subsystem'), install: true) if win32 and get_option('win32-subsystem') != 'console' wrapper_sources= 'osdep/win32-console-wrapper.c' diff --git a/misc/io_utils.c b/misc/io_utils.c index 777e1c780c51a..0b4a258afad5d 100644 --- a/misc/io_utils.c +++ b/misc/io_utils.c @@ -56,32 +56,3 @@ int mp_mkostemps(char *template, int suffixlen, int flags) errno = EEXIST; return -1; } - -bool mp_save_to_file(const char *filepath, const void *data, size_t size) -{ - assert(filepath && data && size); - - bool result = false; - char *tmp = talloc_asprintf(NULL, "%sXXXXXX", filepath); - int fd = mp_mkostemps(tmp, 0, O_CLOEXEC); - if (fd < 0) - goto done; - FILE *cache = fdopen(fd, "wb"); - if (!cache) { - close(fd); - unlink(tmp); - goto done; - } - size_t written = fwrite(data, size, 1, cache); - int ret = fclose(cache); - if (written > 0 && !ret) { - ret = rename(tmp, filepath); - result = !ret; - } else { - unlink(tmp); - } - -done: - talloc_free(tmp); - return result; -} diff --git a/misc/io_utils.rs b/misc/io_utils.rs new file mode 100644 index 0000000000000..35ca56efba1e9 --- /dev/null +++ b/misc/io_utils.rs @@ -0,0 +1,61 @@ +/* + * I/O utility functions + * + * This file is part of mpv. + * + * mpv is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * mpv is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with mpv. If not, see . + */ + +use std::ffi::c_char; +use std::ffi::CStr; +use std::io::Write; +use std::path::Path; +use tempfile::NamedTempFile; + +#[no_mangle] +pub extern "C" fn mp_save_to_file(filepath: *const c_char, data: *const u8, size: usize) -> bool +{ + if filepath.is_null() || data.is_null() || size == 0 { + return false; + } + + let c_str = unsafe { CStr::from_ptr(filepath) }; + let target_path = match c_str.to_str() { + Ok(path) => Path::new(path), + Err(_) => return false, + }; + + let dir = match target_path.parent() { + Some(dir) => dir, + None => return false, + }; + + let filename = match target_path.file_name() { + Some(name) => name, + None => return false, + }; + + let mut temp_file = match NamedTempFile::with_prefix_in(filename, dir) { + Ok(file) => file, + Err(_) => return false, + }; + + // Write data to temporary file + let written = temp_file.write(unsafe { std::slice::from_raw_parts(data, size) }); + if written.is_err() { + return false; + } + + temp_file.persist(&target_path).is_ok() +} diff --git a/player/lua/osc.lua b/player/lua/osc.lua index 8b71b8f9ce3f3..11e2629f9532d 100644 --- a/player/lua/osc.lua +++ b/player/lua/osc.lua @@ -2098,9 +2098,13 @@ local function osc_init() local property = user_opts.remaining_playtime and "playtime-remaining" or "time-remaining" if state.tc_ms then - return (minus..mp.get_property_osd(property .. "/full")) + property = property .. "/full" + end + local value = mp.get_property_osd(property) + if value:sub(1, 1) == "-" then + return "+" .. value:sub(2) else - return (minus..mp.get_property_osd(property)) + return minus .. value end else if state.tc_ms then diff --git a/player/lua/stats.lua b/player/lua/stats.lua index dd3bb24ce2016..afccacf500f3c 100644 --- a/player/lua/stats.lua +++ b/player/lua/stats.lua @@ -657,8 +657,7 @@ end local function add_file(s, print_cache, print_tags) - append(s, "", {prefix="File:", nl="", indent=""}) - append_property(s, "filename", {prefix_sep="", nl="", indent=""}) + append_property(s, "filename", {prefix="File: ", prefix_sep="", nl="", indent=""}) if mp.get_property_osd("filename") ~= mp.get_property_osd("media-title") then append_property(s, "media-title", {prefix="Title:"}) end diff --git a/subprojects/cfg_if.wrap b/subprojects/cfg_if.wrap new file mode 100644 index 0000000000000..c84c4bfc998e5 --- /dev/null +++ b/subprojects/cfg_if.wrap @@ -0,0 +1,6 @@ +[wrap-file] +directory = cfg-if-1.0.0 +source_url = https://crates.io/api/v1/crates/cfg-if/1.0.0/download +source_filename = cfg-if-1.0.0.tar.gz +source_hash = baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd +patch_directory = cfg_if diff --git a/subprojects/critical_section.wrap b/subprojects/critical_section.wrap new file mode 100644 index 0000000000000..b932ae274af8e --- /dev/null +++ b/subprojects/critical_section.wrap @@ -0,0 +1,6 @@ +[wrap-file] +directory = critical-section-1.2.0 +source_url = https://crates.io/api/v1/crates/critical-section/1.2.0/download +source_filename = critical-section-1.2.0.tar.gz +source_hash = 790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b +patch_directory = critical_section diff --git a/subprojects/fastrand.wrap b/subprojects/fastrand.wrap new file mode 100644 index 0000000000000..12916bb6c3590 --- /dev/null +++ b/subprojects/fastrand.wrap @@ -0,0 +1,6 @@ +[wrap-file] +directory = fastrand-2.3.0 +source_url = https://crates.io/api/v1/crates/fastrand/2.3.0/download +source_filename = fastrand-2.3.0.tar.gz +source_hash = 37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be +patch_directory = fastrand diff --git a/subprojects/once_cell.wrap b/subprojects/once_cell.wrap new file mode 100644 index 0000000000000..295ce351a54eb --- /dev/null +++ b/subprojects/once_cell.wrap @@ -0,0 +1,6 @@ +[wrap-file] +directory = once_cell-1.20.3 +source_url = https://crates.io/api/v1/crates/once_cell/1.20.3/download +source_filename = once_cell-1.20.3.tar.gz +source_hash = 945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e +patch_directory = once_cell diff --git a/subprojects/packagefiles/cfg_if/meson.build b/subprojects/packagefiles/cfg_if/meson.build new file mode 100644 index 0000000000000..57b3540fe0104 --- /dev/null +++ b/subprojects/packagefiles/cfg_if/meson.build @@ -0,0 +1,18 @@ +project( + 'cfg_if', + 'rust', + version: '1.0.0', + license: 'MIT OR Apache-2.0', +) + +lib = static_library( + 'cfg_if', + 'src/lib.rs', + override_options: ['rust_std=2021', 'build.rust_std=2021'], + rust_abi: 'rust', + native: true, +) + +cfg_if_dep = declare_dependency( + link_with: [lib], +) diff --git a/subprojects/packagefiles/fastrand/meson.build b/subprojects/packagefiles/fastrand/meson.build new file mode 100644 index 0000000000000..271632ba976ef --- /dev/null +++ b/subprojects/packagefiles/fastrand/meson.build @@ -0,0 +1,24 @@ +project( + 'fastrand', + 'rust', + version: '2.3.0', + license: 'MIT OR Apache-2.0', +) + +rust_args = [ + '--cfg', 'feature="std"', + '--cfg', 'feature="alloc"', +] + +lib = static_library( + 'fastrand', + 'src/lib.rs', + rust_args: rust_args, + override_options: ['rust_std=2021', 'build.rust_std=2021'], + rust_abi: 'rust', + native: true, +) + +fastrand_dep = declare_dependency( + link_with: [lib], +) diff --git a/subprojects/packagefiles/once_cell/meson.build b/subprojects/packagefiles/once_cell/meson.build new file mode 100644 index 0000000000000..7fa67e04e94bb --- /dev/null +++ b/subprojects/packagefiles/once_cell/meson.build @@ -0,0 +1,23 @@ +project( + 'once_cell', + 'rust', + version: '1.20.3', + license: 'MIT OR Apache-2.0', +) + +rust_args = [ + '--cfg', 'feature="std"', +] + +lib = static_library( + 'once_cell', + 'src/lib.rs', + rust_args: rust_args, + override_options: ['rust_std=2021', 'build.rust_std=2021'], + rust_abi: 'rust', + native: true, +) + +once_cell_dep = declare_dependency( + link_with: [lib], +) diff --git a/subprojects/packagefiles/tempfile/meson.build b/subprojects/packagefiles/tempfile/meson.build new file mode 100644 index 0000000000000..0430c864a3687 --- /dev/null +++ b/subprojects/packagefiles/tempfile/meson.build @@ -0,0 +1,39 @@ +project( + 'tempfile', + 'rust', + version: '3.17.1', + license: 'MIT OR Apache-2.0', +) + +rust_args = [ + '-A', 'unused_variables', + '--cfg', 'feature="std"', +] + +cfg_if_dep = dependency('cfg_if', fallback: ['cfg_if', 'cfg_if_dep']) +once_cell_dep = dependency('once_cell', fallback: ['once_cell', 'once_cell_dep']) +fastrand_dep = dependency('fastrand', fallback: ['fastrand', 'fastrand_dep']) + +dependencies = [ + cfg_if_dep, + fastrand_dep, + once_cell_dep, +] + +if win32 + dependencies += dependency('windows_sys', fallback: ['windows_sys', 'windows_sys_dep']) +endif + +lib = static_library( + 'tempfile', + 'src/lib.rs', + rust_args: rust_args, + override_options: ['rust_std=2021', 'build.rust_std=2021'], + rust_abi: 'rust', + native: true, + dependencies: dependencies, +) + +tempfile_dep = declare_dependency( + link_with: [lib], +) diff --git a/subprojects/packagefiles/windows_sys/meson.build b/subprojects/packagefiles/windows_sys/meson.build new file mode 100644 index 0000000000000..fd5179f36528e --- /dev/null +++ b/subprojects/packagefiles/windows_sys/meson.build @@ -0,0 +1,29 @@ +project( + 'windows_sys', + 'rust', + version: '0.59.0', + license: 'MIT OR Apache-2.0', +) + +rust_args = [ + '--cfg', 'feature="Win32"', + '--cfg', 'feature="Win32_Storage"', + '--cfg', 'feature="Win32_Foundation"', + '--cfg', 'feature="Win32_Storage_FileSystem"', +] + +windows_targets_dep = dependency('windows_targets', fallback: ['windows_targets', 'windows_targets_dep']) + +lib = static_library( + 'windows_sys', + 'src/lib.rs', + rust_args: rust_args, + override_options: ['rust_std=2021', 'build.rust_std=2021'], + rust_abi: 'rust', + native: true, + dependencies: [windows_targets_dep], +) + +windows_sys_dep = declare_dependency( + link_with: [lib], +) diff --git a/subprojects/packagefiles/windows_targets/meson.build b/subprojects/packagefiles/windows_targets/meson.build new file mode 100644 index 0000000000000..189607cab5bba --- /dev/null +++ b/subprojects/packagefiles/windows_targets/meson.build @@ -0,0 +1,18 @@ +project( + 'windows_targets', + 'rust', + version: '0.53.0', + license: 'MIT OR Apache-2.0', +) + +lib = static_library( + 'windows_targets', + 'src/lib.rs', + override_options: ['rust_std=2021', 'build.rust_std=2021'], + rust_abi: 'rust', + native: true, +) + +windows_targets_dep = declare_dependency( + link_with: [lib], +) diff --git a/subprojects/portable_atomic.wrap b/subprojects/portable_atomic.wrap new file mode 100644 index 0000000000000..0b9fe85207a6b --- /dev/null +++ b/subprojects/portable_atomic.wrap @@ -0,0 +1,6 @@ +[wrap-file] +directory = portable-atomic-1.10.0 +source_url = https://crates.io/api/v1/crates/portable-atomic/1.10.0/download +source_filename = portable-atomic-1.10.0.tar.gz +source_hash = 280dc24453071f1b63954171985a0b0d30058d287960968b9b2aca264c8d4ee6 +patch_directory = portable_atomic diff --git a/subprojects/tempfile.wrap b/subprojects/tempfile.wrap new file mode 100644 index 0000000000000..69823e43afe1b --- /dev/null +++ b/subprojects/tempfile.wrap @@ -0,0 +1,6 @@ +[wrap-file] +directory = tempfile-3.17.1 +source_url = https://crates.io/api/v1/crates/tempfile/3.17.1/download +source_filename = tempfile-3.17.1.tar.gz +source_hash = 22e5a0acb1f3f55f65cc4a866c361b2fb2a0ff6366785ae6fbb5f85df07ba230 +patch_directory = tempfile diff --git a/subprojects/windows_sys.wrap b/subprojects/windows_sys.wrap new file mode 100644 index 0000000000000..ca26054ebdb06 --- /dev/null +++ b/subprojects/windows_sys.wrap @@ -0,0 +1,6 @@ +[wrap-file] +directory = windows-sys-0.59.0 +source_url = https://crates.io/api/v1/crates/windows-sys/0.59.0/download +source_filename = windows-sys-0.59.0.tar.gz +source_hash = 1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b +patch_directory = windows_sys diff --git a/subprojects/windows_targets.wrap b/subprojects/windows_targets.wrap new file mode 100644 index 0000000000000..679398488e2d0 --- /dev/null +++ b/subprojects/windows_targets.wrap @@ -0,0 +1,6 @@ +[wrap-file] +directory = windows-targets-0.53.0 +source_url = https://crates.io/api/v1/crates/windows-targets/0.53.0/download +source_filename = windows-targets-0.53.0.tar.gz +source_hash = b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b +patch_directory = windows_targets