diff --git a/src/autoload.rs b/src/autoload.rs index 323f70a7d..74f3c68f0 100644 --- a/src/autoload.rs +++ b/src/autoload.rs @@ -325,7 +325,7 @@ fn test_autoload() { use crate::common::{charptr2wcstring, wcs2zstring, write_loop}; use crate::fds::wopen_cloexec; use crate::wutil::sprintf; - use libc::{O_CREAT, O_RDWR}; + use nix::fcntl::OFlag; macro_rules! run { ( $fmt:expr $(, $arg:expr )* $(,)? ) => { @@ -340,7 +340,7 @@ fn touch_file(path: &wstr) { let fd = wopen_cloexec( path, - O_RDWR | O_CREAT, + OFlag::O_RDWR | OFlag::O_CREAT, Mode::S_IRUSR | Mode::S_IWUSR | Mode::S_IRGRP diff --git a/src/builtins/cd.rs b/src/builtins/cd.rs index ccb461ef7..fbba18eb9 100644 --- a/src/builtins/cd.rs +++ b/src/builtins/cd.rs @@ -8,8 +8,8 @@ wutil::{normalize_path, wperror, wreadlink}, }; use errno::{self, Errno}; -use libc::{fchdir, EACCES, ELOOP, ENOENT, ENOTDIR, EPERM, O_RDONLY}; -use nix::sys::stat::Mode; +use libc::{fchdir, EACCES, ELOOP, ENOENT, ENOTDIR, EPERM}; +use nix::{fcntl::OFlag, sys::stat::Mode}; use std::{os::fd::AsRawFd, sync::Arc}; // The cd builtin. Changes the current directory to the one specified or to $HOME if none is @@ -87,7 +87,7 @@ pub fn cd(parser: &Parser, streams: &mut IoStreams, args: &mut [&wstr]) -> Optio errno::set_errno(Errno(0)); - let res = wopen_cloexec(&norm_dir, O_RDONLY, Mode::empty()) + let res = wopen_cloexec(&norm_dir, OFlag::O_RDONLY, Mode::empty()) .map(AutoCloseFd::new) .map_err(|err| err as i32); diff --git a/src/builtins/source.rs b/src/builtins/source.rs index f3b6c5e95..d39dbdd52 100644 --- a/src/builtins/source.rs +++ b/src/builtins/source.rs @@ -7,8 +7,8 @@ parser::Block, reader::reader_read, }; -use libc::{c_int, O_RDONLY, S_IFMT, S_IFREG}; -use nix::sys::stat::Mode; +use libc::{c_int, S_IFMT, S_IFREG}; +use nix::{fcntl::OFlag, sys::stat::Mode}; use super::prelude::*; @@ -51,7 +51,7 @@ pub fn source(parser: &Parser, streams: &mut IoStreams, args: &mut [&wstr]) -> O func_filename = FilenameRef::new(L!("-").to_owned()); fd = streams.stdin_fd; } else { - let Ok(raw_fd) = wopen_cloexec(args[optind], O_RDONLY, Mode::empty()) else { + let Ok(raw_fd) = wopen_cloexec(args[optind], OFlag::O_RDONLY, Mode::empty()) else { let esc = escape(args[optind]); streams.err.append(wgettext_fmt!( "%ls: Error encountered while sourcing file '%ls':\n", diff --git a/src/env_universal_common.rs b/src/env_universal_common.rs index 0ca6f3034..b8673be91 100644 --- a/src/env_universal_common.rs +++ b/src/env_universal_common.rs @@ -19,8 +19,8 @@ wunlink, FileId, INVALID_FILE_ID, }; use errno::{errno, Errno}; -use libc::{EINTR, LOCK_EX, O_CREAT, O_RDONLY, O_RDWR}; -use nix::sys::stat::Mode; +use libc::{EINTR, LOCK_EX}; +use nix::{fcntl::OFlag, sys::stat::Mode}; use std::collections::hash_map::Entry; use std::collections::HashSet; use std::ffi::CString; @@ -30,10 +30,10 @@ // Pull in the O_EXLOCK constant if it is defined, otherwise set it to 0. #[cfg(any(bsd, target_os = "macos"))] -use libc::O_EXLOCK; +const O_EXLOCK: OFlag = OFlag::O_EXLOCK; #[cfg(not(any(bsd, target_os = "macos")))] -const O_EXLOCK: libc::c_int = 0; +const O_EXLOCK: OFlag = OFlag::empty(); /// Callback data, reflecting a change in universal variables. pub struct CallbackData { @@ -389,7 +389,8 @@ fn load_from_path_narrow(&mut self, callbacks: &mut CallbackDataList) -> bool { return true; } - let Ok(raw_fd) = open_cloexec(&self.narrow_vars_path, O_RDONLY, Mode::empty()) else { + let Ok(raw_fd) = open_cloexec(&self.narrow_vars_path, OFlag::O_RDONLY, Mode::empty()) + else { return false; }; @@ -433,9 +434,9 @@ fn open_and_acquire_lock(&mut self) -> Option { // We pass O_RDONLY with O_CREAT; this creates a potentially empty file. We do this so that we // have something to lock on. let mut locked_by_open = false; - let mut flags = O_RDWR | O_CREAT; + let mut flags = OFlag::O_RDWR | OFlag::O_CREAT; - if O_EXLOCK != 0 && self.do_flock { + if !O_EXLOCK.is_empty() && self.do_flock { flags |= O_EXLOCK; locked_by_open = true; } @@ -453,8 +454,8 @@ fn open_and_acquire_lock(&mut self) -> Option { continue; // signaled; try again } - if O_EXLOCK != 0 { - if (flags & O_EXLOCK) != 0 + if !O_EXLOCK.is_empty() { + if flags.intersects(O_EXLOCK) && [nix::Error::ENOTSUP, nix::Error::EOPNOTSUPP].contains(&err) { // Filesystem probably does not support locking. Give up on locking. diff --git a/src/exec.rs b/src/exec.rs index 2d7088ebd..149e884f9 100644 --- a/src/exec.rs +++ b/src/exec.rs @@ -50,9 +50,10 @@ use crate::wutil::{wgettext, wgettext_fmt}; use errno::{errno, set_errno}; use libc::{ - c_char, EACCES, ENOENT, ENOEXEC, ENOTDIR, EPIPE, EXIT_FAILURE, EXIT_SUCCESS, O_NOCTTY, - O_RDONLY, STDERR_FILENO, STDIN_FILENO, STDOUT_FILENO, + c_char, EACCES, ENOENT, ENOEXEC, ENOTDIR, EPIPE, EXIT_FAILURE, EXIT_SUCCESS, STDERR_FILENO, + STDIN_FILENO, STDOUT_FILENO, }; +use nix::fcntl::OFlag; use nix::sys::stat; use std::ffi::CStr; use std::io::{Read, Write}; @@ -367,7 +368,7 @@ pub fn is_thompson_shell_script(path: &CStr) -> bool { } let e = errno(); let mut res = false; - let fd = open_cloexec(path, O_RDONLY | O_NOCTTY, stat::Mode::empty()); + let fd = open_cloexec(path, OFlag::O_RDONLY | OFlag::O_NOCTTY, stat::Mode::empty()); if let Ok(fd) = fd { let mut file = unsafe { std::fs::File::from_raw_fd(fd) }; let mut buf = [b'\0'; 256]; diff --git a/src/fds.rs b/src/fds.rs index eee768e21..f976d97ea 100644 --- a/src/fds.rs +++ b/src/fds.rs @@ -224,15 +224,14 @@ pub fn set_cloexec(fd: RawFd, should_set: bool /* = true */) -> c_int { /// possible). pub fn wopen_cloexec( pathname: &wstr, - flags: i32, + flags: OFlag, mode: nix::sys::stat::Mode, ) -> nix::Result { open_cloexec(wcs2zstring(pathname).as_c_str(), flags, mode) } /// Narrow versions of wopen_cloexec. -pub fn open_cloexec(path: &CStr, flags: i32, mode: nix::sys::stat::Mode) -> nix::Result { - let flags = unsafe { OFlag::from_bits_unchecked(flags) }; +pub fn open_cloexec(path: &CStr, flags: OFlag, mode: nix::sys::stat::Mode) -> nix::Result { // Port note: the C++ version of this function had a fallback for platforms where // O_CLOEXEC is not supported, using fcntl. In 2023, this is no longer needed. let saved_errno = errno(); diff --git a/src/history.rs b/src/history.rs index f764bddc0..c168a2fff 100644 --- a/src/history.rs +++ b/src/history.rs @@ -31,12 +31,9 @@ }; use bitflags::bitflags; -use libc::{ - fchmod, fchown, flock, fstat, ftruncate, lseek, LOCK_EX, LOCK_SH, LOCK_UN, O_APPEND, O_CREAT, - O_RDONLY, O_WRONLY, SEEK_SET, -}; +use libc::{fchmod, fchown, flock, fstat, ftruncate, lseek, LOCK_EX, LOCK_SH, LOCK_UN, SEEK_SET}; use lru::LruCache; -use nix::sys::stat::Mode; +use nix::{fcntl::OFlag, sys::stat::Mode}; use rand::Rng; use crate::{ @@ -481,7 +478,7 @@ fn load_old_if_needed(&mut self) { let _profiler = TimeProfiler::new("load_old"); if let Some(filename) = history_filename(&self.name, L!("")) { - let Ok(raw_fd) = wopen_cloexec(&filename, O_RDONLY, Mode::empty()) else { + let Ok(raw_fd) = wopen_cloexec(&filename, OFlag::O_RDONLY, Mode::empty()) else { return; }; @@ -674,9 +671,12 @@ fn save_internal_via_rewrite(&mut self) { break; } - let target_fd_before = - wopen_cloexec(&target_name, O_RDONLY | O_CREAT, HISTORY_FILE_MODE) - .map(|raw_fd| unsafe { OwnedFd::from_raw_fd(raw_fd) }); + let target_fd_before = wopen_cloexec( + &target_name, + OFlag::O_RDONLY | OFlag::O_CREAT, + HISTORY_FILE_MODE, + ) + .map(|raw_fd| unsafe { OwnedFd::from_raw_fd(raw_fd) }); let orig_file_id = target_fd_before .as_ref() @@ -698,7 +698,7 @@ fn save_internal_via_rewrite(&mut self) { // If the open fails, then proceed; this may be because there is no current history let mut new_file_id = INVALID_FILE_ID; - let target_fd_after = wopen_cloexec(&target_name, O_RDONLY, Mode::empty()) + let target_fd_after = wopen_cloexec(&target_name, OFlag::O_RDONLY, Mode::empty()) .map(|raw_fd| unsafe { OwnedFd::from_raw_fd(raw_fd) }); if let Ok(target_fd_after) = target_fd_after.as_ref() { @@ -815,7 +815,11 @@ fn save_internal_via_appending(&mut self) -> bool { // Limit our max tries so we don't do this forever. let mut history_fd = None; for _i in 0..MAX_SAVE_TRIES { - let Ok(fd) = wopen_cloexec(&history_path, O_WRONLY | O_APPEND, Mode::empty()) else { + let Ok(fd) = wopen_cloexec( + &history_path, + OFlag::O_WRONLY | OFlag::O_APPEND, + Mode::empty(), + ) else { // can't open, we're hosed break; }; @@ -1106,7 +1110,7 @@ fn populate_from_config_path(&mut self) { old_file.push_utfstr(&self.name); old_file.push_str("_history"); - let Ok(src_fd) = wopen_cloexec(&old_file, O_RDONLY, Mode::empty()) else { + let Ok(src_fd) = wopen_cloexec(&old_file, OFlag::O_RDONLY, Mode::empty()) else { return; }; @@ -1116,7 +1120,11 @@ fn populate_from_config_path(&mut self) { // destination file descriptor, since it destroys the name and the file. self.clear(); - let Ok(dst_fd) = wopen_cloexec(&new_file, O_WRONLY | O_CREAT, HISTORY_FILE_MODE) else { + let Ok(dst_fd) = wopen_cloexec( + &new_file, + OFlag::O_WRONLY | OFlag::O_CREAT, + HISTORY_FILE_MODE, + ) else { FLOG!(history_file, "Error when writing history file"); return; }; diff --git a/src/io.rs b/src/io.rs index 9be8a0683..c140904c6 100644 --- a/src/io.rs +++ b/src/io.rs @@ -17,7 +17,8 @@ use crate::wchar::prelude::*; use crate::wutil::{perror, perror_io, wdirname, wstat, wwrite_to_fd}; use errno::Errno; -use libc::{EAGAIN, EINTR, ENOENT, ENOTDIR, EPIPE, EWOULDBLOCK, O_EXCL, STDOUT_FILENO}; +use libc::{EAGAIN, EINTR, ENOENT, ENOTDIR, EPIPE, EWOULDBLOCK, STDOUT_FILENO}; +use nix::fcntl::OFlag; use nix::sys::stat::Mode; use std::cell::{RefCell, UnsafeCell}; use std::os::fd::RawFd; @@ -665,7 +666,7 @@ pub fn append_from_specs(&mut self, specs: &RedirectionSpecList, pwd: &wstr) -> self.push(Arc::new(IoFile::new(spec.fd, file))); } Err(err) => { - if (oflags & O_EXCL) != 0 && err == nix::Error::EEXIST { + if oflags.intersects(OFlag::O_EXCL) && err == nix::Error::EEXIST { FLOGF!(warning, NOCLOB_ERROR, spec.target); } else { if should_flog!(warning) { diff --git a/src/parser.rs b/src/parser.rs index 0a29cfaac..8148e7a4d 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -33,7 +33,7 @@ use crate::wchar::{wstr, WString, L}; use crate::wutil::{perror, wgettext, wgettext_fmt}; use libc::c_int; -use libc::O_RDONLY; +use nix::fcntl::OFlag; use nix::sys::stat::Mode; use once_cell::sync::Lazy; use printf_compat::sprintf; @@ -361,7 +361,7 @@ pub fn new(variables: EnvStackRef, is_principal: bool) -> ParserRef { match open_cloexec( CStr::from_bytes_with_nul(b".\0").unwrap(), - O_RDONLY, + OFlag::O_RDONLY, Mode::empty(), ) { Ok(raw_fd) => { diff --git a/src/reader.rs b/src/reader.rs index 280ff848e..febf586ee 100644 --- a/src/reader.rs +++ b/src/reader.rs @@ -17,6 +17,7 @@ IXOFF, IXON, ONLCR, OPOST, O_NONBLOCK, O_RDONLY, SIGINT, SIGTTIN, STDIN_FILENO, STDOUT_FILENO, S_IFDIR, TCSANOW, VMIN, VQUIT, VSUSP, VTIME, _POSIX_VDISABLE, }; +use nix::fcntl::OFlag; use nix::sys::stat::Mode; use once_cell::sync::Lazy; use std::cell::UnsafeCell; @@ -4660,7 +4661,7 @@ fn import_history_if_necessary(&mut self) { var.map_or_else(|| L!("~/.bash_history").to_owned(), |var| var.as_string()); expand_tilde(&mut path, self.vars()); - let Ok(raw_fd) = wopen_cloexec(&path, O_RDONLY, Mode::empty()) else { + let Ok(raw_fd) = wopen_cloexec(&path, OFlag::O_RDONLY, Mode::empty()) else { return; }; diff --git a/src/redirection.rs b/src/redirection.rs index 2a8211b38..6ec0e50b8 100644 --- a/src/redirection.rs +++ b/src/redirection.rs @@ -3,7 +3,7 @@ use crate::io::IoChain; use crate::wchar::prelude::*; use crate::wutil::fish_wcstoi; -use libc::{c_int, O_APPEND, O_CREAT, O_EXCL, O_RDONLY, O_TRUNC, O_WRONLY}; +use nix::fcntl::OFlag; use std::os::fd::RawFd; #[derive(Clone, Copy, Debug, Eq, PartialEq)] @@ -33,12 +33,12 @@ pub struct Dup2List { impl RedirectionMode { /// The open flags for this redirection mode. - pub fn oflags(self) -> Option { + pub fn oflags(self) -> Option { match self { - RedirectionMode::append => Some(O_CREAT | O_APPEND | O_WRONLY), - RedirectionMode::overwrite => Some(O_CREAT | O_WRONLY | O_TRUNC), - RedirectionMode::noclob => Some(O_CREAT | O_EXCL | O_WRONLY), - RedirectionMode::input => Some(O_RDONLY), + RedirectionMode::append => Some(OFlag::O_CREAT | OFlag::O_APPEND | OFlag::O_WRONLY), + RedirectionMode::overwrite => Some(OFlag::O_CREAT | OFlag::O_WRONLY | OFlag::O_TRUNC), + RedirectionMode::noclob => Some(OFlag::O_CREAT | OFlag::O_EXCL | OFlag::O_WRONLY), + RedirectionMode::input => Some(OFlag::O_RDONLY), _ => None, } } @@ -83,7 +83,7 @@ pub fn get_target_as_fd(&self) -> Option { } /// \return the open flags for this redirection. - pub fn oflags(&self) -> c_int { + pub fn oflags(&self) -> OFlag { match self.mode.oflags() { Some(flags) => flags, None => panic!("Not a file redirection"), diff --git a/src/tests/history.rs b/src/tests/history.rs index 0e645715f..ea6f29f29 100644 --- a/src/tests/history.rs +++ b/src/tests/history.rs @@ -7,8 +7,7 @@ use crate::tests::string_escape::ESCAPE_TEST_CHAR; use crate::wchar::prelude::*; use crate::wcstringutil::{string_prefixes_string, string_prefixes_string_case_insensitive}; -use libc::O_RDONLY; -use nix::sys::stat::Mode; +use nix::{fcntl::OFlag, sys::stat::Mode}; use rand::random; use std::collections::VecDeque; use std::ffi::CString; @@ -596,7 +595,12 @@ fn test_history_formats() { ]; let test_history_imported_from_bash = History::with_name(L!("bash_import")); let file = AutoCloseFd::new( - wopen_cloexec(L!("tests/history_sample_bash"), O_RDONLY, Mode::empty()).unwrap(), + wopen_cloexec( + L!("tests/history_sample_bash"), + OFlag::O_RDONLY, + Mode::empty(), + ) + .unwrap(), ); test_history_imported_from_bash.populate_from_bash(BufReader::new(file)); assert_eq!(test_history_imported_from_bash.get_history(), expected); diff --git a/src/tokenizer.rs b/src/tokenizer.rs index f34892298..bc8b12c4c 100644 --- a/src/tokenizer.rs +++ b/src/tokenizer.rs @@ -6,7 +6,8 @@ use crate::parse_constants::SOURCE_OFFSET_INVALID; use crate::redirection::RedirectionMode; use crate::wchar::prelude::*; -use libc::{c_int, STDIN_FILENO, STDOUT_FILENO}; +use libc::{STDIN_FILENO, STDOUT_FILENO}; +use nix::fcntl::OFlag; use std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, Not}; use std::os::fd::RawFd; @@ -1036,8 +1037,8 @@ fn try_from(buff: &wstr) -> Result { impl PipeOrRedir { /// \return the oflags (as in open(2)) for this redirection. - pub fn oflags(&self) -> c_int { - self.mode.oflags().unwrap_or(-1) + pub fn oflags(&self) -> Option { + self.mode.oflags() } // \return if we are "valid". Here "valid" means only that the source fd did not overflow.