Skip to content

Commit

Permalink
misc/io_utils.rs: add rust impl of atomic file save
Browse files Browse the repository at this point in the history
  • Loading branch information
kasper93 committed Feb 21, 2025
1 parent e32beaa commit 3e72cf3
Show file tree
Hide file tree
Showing 19 changed files with 279 additions and 36 deletions.
15 changes: 12 additions & 3 deletions meson.build
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
project('mpv',
'c',
['c', 'rust'],
license: ['GPL2+', 'LGPL2.1+'],
version: files('./MPV_VERSION'),
meson_version: '>=1.3.0',
Expand All @@ -11,6 +11,8 @@ project('mpv',
'cpp_std=c++20',
'cpp_eh=default',
'warning_level=2',
'rust_std=2021',
'build.rust_std=2021',
]
)

Expand Down Expand Up @@ -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'),
Expand All @@ -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

Expand Down Expand Up @@ -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'
Expand Down
29 changes: 0 additions & 29 deletions misc/io_utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
61 changes: 61 additions & 0 deletions misc/io_utils.rs
Original file line number Diff line number Diff line change
@@ -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 <http://www.gnu.org/licenses/>.
*/

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()
}
8 changes: 6 additions & 2 deletions player/lua/osc.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 1 addition & 2 deletions player/lua/stats.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 6 additions & 0 deletions subprojects/cfg_if.wrap
Original file line number Diff line number Diff line change
@@ -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
6 changes: 6 additions & 0 deletions subprojects/critical_section.wrap
Original file line number Diff line number Diff line change
@@ -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
6 changes: 6 additions & 0 deletions subprojects/fastrand.wrap
Original file line number Diff line number Diff line change
@@ -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
6 changes: 6 additions & 0 deletions subprojects/once_cell.wrap
Original file line number Diff line number Diff line change
@@ -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
18 changes: 18 additions & 0 deletions subprojects/packagefiles/cfg_if/meson.build
Original file line number Diff line number Diff line change
@@ -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],
)
24 changes: 24 additions & 0 deletions subprojects/packagefiles/fastrand/meson.build
Original file line number Diff line number Diff line change
@@ -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],
)
23 changes: 23 additions & 0 deletions subprojects/packagefiles/once_cell/meson.build
Original file line number Diff line number Diff line change
@@ -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],
)
39 changes: 39 additions & 0 deletions subprojects/packagefiles/tempfile/meson.build
Original file line number Diff line number Diff line change
@@ -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],
)
29 changes: 29 additions & 0 deletions subprojects/packagefiles/windows_sys/meson.build
Original file line number Diff line number Diff line change
@@ -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],
)
18 changes: 18 additions & 0 deletions subprojects/packagefiles/windows_targets/meson.build
Original file line number Diff line number Diff line change
@@ -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],
)
6 changes: 6 additions & 0 deletions subprojects/portable_atomic.wrap
Original file line number Diff line number Diff line change
@@ -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
6 changes: 6 additions & 0 deletions subprojects/tempfile.wrap
Original file line number Diff line number Diff line change
@@ -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
6 changes: 6 additions & 0 deletions subprojects/windows_sys.wrap
Original file line number Diff line number Diff line change
@@ -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
6 changes: 6 additions & 0 deletions subprojects/windows_targets.wrap
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 3e72cf3

Please sign in to comment.