Skip to content

Commit 58a6eb6

Browse files
committed
Convert fish_mkstemp_cloexec() to return an OwnedFd
1 parent cfe9881 commit 58a6eb6

File tree

4 files changed

+49
-58
lines changed

4 files changed

+49
-58
lines changed

src/env_universal_common.rs

Lines changed: 32 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ use crate::common::{
66
};
77
use crate::env::{EnvVar, EnvVarFlags, VarTable};
88
use crate::fallback::fish_mkstemp_cloexec;
9-
use crate::fds::AutoCloseFd;
109
use crate::fds::{open_cloexec, wopen_cloexec};
1110
use crate::flog::{FLOG, FLOGF};
1211
use crate::path::path_get_config;
@@ -493,39 +492,41 @@ impl EnvUniversal {
493492
res_fd
494493
}
495494

496-
fn open_temporary_file(&mut self, directory: &wstr, out_path: &mut WString) -> AutoCloseFd {
495+
fn open_temporary_file(&mut self, directory: &wstr, out_path: &mut WString) -> OwnedFd {
497496
// Create and open a temporary file for writing within the given directory. Try to create a
498497
// temporary file, up to 10 times. We don't use mkstemps because we want to open it CLO_EXEC.
499498
// This should almost always succeed on the first try.
500499
assert!(!string_suffixes_string(L!("/"), directory));
501500

502-
let mut saved_errno = Errno(0);
501+
let mut attempt = 0;
503502
let tmp_name_template = directory.to_owned() + L!("/fishd.tmp.XXXXXX");
504-
let mut result = AutoCloseFd::empty();
505-
let mut narrow_str = CString::default();
506-
for _attempt in 0..10 {
507-
if result.is_valid() {
508-
break;
503+
let result = loop {
504+
attempt += 1;
505+
let result = fish_mkstemp_cloexec(wcs2zstring(&tmp_name_template));
506+
match (result, attempt) {
507+
(Ok(r), _) => break r,
508+
(Err(e), 10) => {
509+
FLOG!(
510+
error,
511+
// We previously used to log a copy of the buffer we expected mk(o)stemp to
512+
// update with the new path, but mkstemp(3) says the contents of the buffer
513+
// are undefined in case of EEXIST, but left unchanged in case of EINVAL. So
514+
// just log the original template we pass in to the function instead.
515+
wgettext_fmt!(
516+
"Unable to create temporary file '%ls': %s",
517+
&tmp_name_template,
518+
e.to_string()
519+
)
520+
);
521+
}
522+
_ => continue,
509523
}
510-
let (fd, tmp_name) = fish_mkstemp_cloexec(wcs2zstring(&tmp_name_template));
511-
result.reset(fd);
512-
narrow_str = tmp_name;
513-
saved_errno = errno();
514-
}
515-
*out_path = str2wcstring(narrow_str.as_bytes());
524+
};
516525

517-
if !result.is_valid() {
518-
FLOG!(
519-
error,
520-
wgettext_fmt!(
521-
"Unable to open temporary file '%ls': %s",
522-
out_path,
523-
saved_errno.to_string()
524-
)
525-
);
526-
}
527-
result
526+
*out_path = str2wcstring(result.1.as_bytes());
527+
result.0
528528
}
529+
529530
/// Writes our state to the fd. path is provided only for error reporting.
530531
fn write_to_fd(&mut self, fd: RawFd, path: &wstr) -> bool {
531532
assert!(fd >= 0);
@@ -753,19 +754,11 @@ impl EnvUniversal {
753754

754755
// Open adjacent temporary file.
755756
let private_fd = self.open_temporary_file(directory, &mut private_file_path);
756-
let mut success = private_fd.is_valid();
757-
758-
if !success {
759-
FLOG!(uvar_file, "universal log open_temporary_file() failed");
760-
}
761757

762758
// Write to it.
763-
if success {
764-
assert!(private_fd.is_valid());
765-
success = self.write_to_fd(private_fd.fd(), &private_file_path);
766-
if !success {
767-
FLOG!(uvar_file, "universal log write_to_fd() failed");
768-
}
759+
let mut success = self.write_to_fd(private_fd.as_raw_fd(), &private_file_path);
760+
if !success {
761+
FLOG!(uvar_file, "universal log write_to_fd() failed");
769762
}
770763

771764
if success {
@@ -774,12 +767,12 @@ impl EnvUniversal {
774767
// Ensure we maintain ownership and permissions (#2176).
775768
// let mut sbuf : libc::stat = MaybeUninit::uninit();
776769
if let Ok(md) = wstat(&real_path) {
777-
if unsafe { libc::fchown(private_fd.fd(), md.uid(), md.gid()) } == -1 {
770+
if unsafe { libc::fchown(private_fd.as_raw_fd(), md.uid(), md.gid()) } == -1 {
778771
FLOG!(uvar_file, "universal log fchown() failed");
779772
}
780773
#[allow(clippy::useless_conversion)]
781774
let mode: libc::mode_t = md.mode().try_into().unwrap();
782-
if unsafe { libc::fchmod(private_fd.fd(), mode) } == -1 {
775+
if unsafe { libc::fchmod(private_fd.as_raw_fd(), mode) } == -1 {
783776
FLOG!(uvar_file, "universal log fchmod() failed");
784777
}
785778
}
@@ -802,7 +795,7 @@ impl EnvUniversal {
802795
times[0].tv_nsec = libc::UTIME_OMIT; // don't change ctime
803796
if unsafe { libc::clock_gettime(libc::CLOCK_REALTIME, &mut times[1]) } != 0 {
804797
unsafe {
805-
libc::futimens(private_fd.fd(), &times[0]);
798+
libc::futimens(private_fd.as_raw_fd(), &times[0]);
806799
}
807800
}
808801
}

src/fallback.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@
55
66
use crate::widecharwidth::{WcLookupTable, WcWidth};
77
use crate::{common::is_console_session, wchar::prelude::*};
8+
use errno::{errno, Errno};
89
use once_cell::sync::Lazy;
910
use std::cmp;
11+
use std::os::fd::{FromRawFd, OwnedFd};
1012
use std::sync::atomic::{AtomicIsize, Ordering};
11-
use std::{ffi::CString, mem, os::fd::RawFd};
13+
use std::{ffi::CString, mem};
1214

1315
/// Width of ambiguous East Asian characters and, as of TR11, all private-use characters.
1416
/// 1 is the typical default, but we accept any non-negative override via `$fish_ambiguous_width`.
@@ -100,7 +102,7 @@ pub fn fish_wcswidth(s: &wstr) -> isize {
100102
// Replacement for mkostemp(str, O_CLOEXEC)
101103
// This uses mkostemp if available,
102104
// otherwise it uses mkstemp followed by fcntl
103-
pub fn fish_mkstemp_cloexec(name_template: CString) -> (RawFd, CString) {
105+
pub fn fish_mkstemp_cloexec(name_template: CString) -> Result<(OwnedFd, CString), Errno> {
104106
let name = name_template.into_raw();
105107
#[cfg(not(target_os = "macos"))]
106108
let fd = {
@@ -116,7 +118,11 @@ pub fn fish_mkstemp_cloexec(name_template: CString) -> (RawFd, CString) {
116118
}
117119
fd
118120
};
119-
(fd, unsafe { CString::from_raw(name) })
121+
if fd == -1 {
122+
Err(errno())
123+
} else {
124+
unsafe { Ok((OwnedFd::from_raw_fd(fd), CString::from_raw(name))) }
125+
}
120126
}
121127

122128
pub fn wcscasecmp(lhs: &wstr, rhs: &wstr) -> cmp::Ordering {

src/history.rs

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ use std::{
2525
mem,
2626
num::NonZeroUsize,
2727
ops::ControlFlow,
28-
os::fd::{AsFd, AsRawFd, RawFd},
28+
os::fd::{AsFd, AsRawFd, OwnedFd, RawFd},
2929
sync::{Arc, Mutex, MutexGuard},
3030
time::{Duration, SystemTime, UNIX_EPOCH},
3131
};
@@ -45,7 +45,7 @@ use crate::{
4545
env::{EnvMode, EnvStack, Environment},
4646
expand::{expand_one, ExpandFlags},
4747
fallback::fish_mkstemp_cloexec,
48-
fds::{wopen_cloexec, AutoCloseFd},
48+
fds::wopen_cloexec,
4949
flog::{FLOG, FLOGF},
5050
global_safety::RelaxedAtomicBool,
5151
history::file::{append_history_item_to_buffer, HistoryFileContents},
@@ -658,8 +658,7 @@ impl HistoryImpl {
658658
let Some((tmp_file, tmp_name)) = create_temporary_file(&tmp_name_template) else {
659659
return;
660660
};
661-
let tmp_fd = tmp_file.fd();
662-
assert!(tmp_fd >= 0);
661+
let tmp_fd = tmp_file.as_raw_fd();
663662
let mut done = false;
664663
for _i in 0..MAX_SAVE_TRIES {
665664
if done {
@@ -1363,13 +1362,11 @@ impl HistoryImpl {
13631362
}
13641363

13651364
// Returns the fd of an opened temporary file, or None on failure.
1366-
fn create_temporary_file(name_template: &wstr) -> Option<(AutoCloseFd, WString)> {
1365+
fn create_temporary_file(name_template: &wstr) -> Option<(OwnedFd, WString)> {
13671366
for _attempt in 0..10 {
13681367
let narrow_str = wcs2zstring(name_template);
1369-
let (fd, narrow_str) = fish_mkstemp_cloexec(narrow_str);
1370-
let out_fd = AutoCloseFd::new(fd);
1371-
if out_fd.is_valid() {
1372-
return Some((out_fd, str2wcstring(narrow_str.to_bytes())));
1368+
if let Ok((fd, narrow_str)) = fish_mkstemp_cloexec(narrow_str) {
1369+
return Some((fd, str2wcstring(narrow_str.to_bytes())));
13731370
}
13741371
}
13751372
None

src/wutil/tests.rs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -60,13 +60,8 @@ fn test_wdirname_wbasename() {
6060
#[serial]
6161
fn test_wwrite_to_fd() {
6262
test_init();
63-
let (fd, filename) =
64-
fish_mkstemp_cloexec(CString::new("/tmp/fish_test_wwrite.XXXXXX").unwrap());
65-
{
66-
let mut tmpfd = AutoCloseFd::new(fd);
67-
assert!(tmpfd.is_valid());
68-
tmpfd.close();
69-
}
63+
let (_fd, filename) =
64+
fish_mkstemp_cloexec(CString::new("/tmp/fish_test_wwrite.XXXXXX").unwrap()).unwrap();
7065
let sizes = [1, 2, 3, 5, 13, 23, 64, 128, 255, 4096, 4096 * 2];
7166
for &size in &sizes {
7267
let fd = AutoCloseFd::new(unsafe {

0 commit comments

Comments
 (0)