Skip to content

Commit

Permalink
Add chflags
Browse files Browse the repository at this point in the history
  • Loading branch information
musikid authored and asomers committed Jul 10, 2022
1 parent caebe66 commit fc16951
Show file tree
Hide file tree
Showing 5 changed files with 177 additions and 1 deletion.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Expand Up @@ -6,9 +6,10 @@ This project adheres to [Semantic Versioning](https://semver.org/).
## [Unreleased] - ReleaseDate
### Added

- Added `chflags`.
(#[1758](https://github.com/nix-rust/nix/pull/1758))
- Added `aio_writev` and `aio_readv`.
(#[1713](https://github.com/nix-rust/nix/pull/1713))

- impl `From<uid_t>` for `Uid` and `From<gid_t>` for `Gid`
(#[1727](https://github.com/nix-rust/nix/pull/1727))
- impl From<SockaddrIn> for std::net::SocketAddrV4 and
Expand Down
112 changes: 112 additions & 0 deletions src/sys/stat.rs
@@ -1,4 +1,12 @@
pub use libc::{dev_t, mode_t};
#[cfg(any(target_os = "macos", target_os = "ios", target_os = "openbsd"))]
pub use libc::c_uint;
#[cfg(any(
target_os = "netbsd",
target_os = "freebsd",
target_os = "dragonfly"
))]
pub use libc::c_ulong;
pub use libc::stat as FileStat;

use crate::{Result, NixPath, errno::Errno};
Expand Down Expand Up @@ -43,6 +51,110 @@ libc_bitflags! {
}
}

#[cfg(any(target_os = "macos", target_os = "ios", target_os="openbsd"))]
pub type type_of_file_flag = c_uint;
#[cfg(any(
target_os = "netbsd",
target_os = "freebsd",
target_os = "dragonfly"
))]
pub type type_of_file_flag = c_ulong;

#[cfg(any(
target_os = "openbsd",
target_os = "netbsd",
target_os = "freebsd",
target_os = "dragonfly",
target_os = "macos",
target_os = "ios"
))]
libc_bitflags! {
/// File flags.
#[cfg_attr(docsrs, doc(cfg(all())))]
pub struct FileFlag: type_of_file_flag {
/// The file may only be appended to.
SF_APPEND;
/// The file has been archived.
SF_ARCHIVED;
#[cfg(any(target_os = "dragonfly"))]
SF_CACHE;
/// The file may not be changed.
SF_IMMUTABLE;
/// Indicates a WAPBL journal file.
#[cfg(any(target_os = "netbsd"))]
SF_LOG;
/// Do not retain history for file
#[cfg(any(target_os = "dragonfly"))]
SF_NOHISTORY;
/// The file may not be renamed or deleted.
#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
SF_NOUNLINK;
/// Mask of superuser changeable flags
SF_SETTABLE;
/// Snapshot is invalid.
#[cfg(any(target_os = "netbsd"))]
SF_SNAPINVAL;
/// The file is a snapshot file.
#[cfg(any(target_os = "netbsd", target_os = "freebsd"))]
SF_SNAPSHOT;
#[cfg(any(target_os = "dragonfly"))]
SF_XLINK;
/// The file may only be appended to.
UF_APPEND;
/// The file needs to be archived.
#[cfg(any(target_os = "freebsd"))]
UF_ARCHIVE;
#[cfg(any(target_os = "dragonfly"))]
UF_CACHE;
/// File is compressed at the file system level.
#[cfg(any(target_os = "macos", target_os = "ios"))]
UF_COMPRESSED;
/// The file may be hidden from directory listings at the application's
/// discretion.
#[cfg(any(
target_os = "freebsd",
target_os = "macos",
target_os = "ios",
))]
UF_HIDDEN;
/// The file may not be changed.
UF_IMMUTABLE;
/// Do not dump the file.
UF_NODUMP;
#[cfg(any(target_os = "dragonfly"))]
UF_NOHISTORY;
/// The file may not be renamed or deleted.
#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
UF_NOUNLINK;
/// The file is offline, or has the Windows and CIFS
/// `FILE_ATTRIBUTE_OFFLINE` attribute.
#[cfg(any(target_os = "freebsd"))]
UF_OFFLINE;
/// The directory is opaque when viewed through a union stack.
UF_OPAQUE;
/// The file is read only, and may not be written or appended.
#[cfg(any(target_os = "freebsd"))]
UF_READONLY;
/// The file contains a Windows reparse point.
#[cfg(any(target_os = "freebsd"))]
UF_REPARSE;
/// Mask of owner changeable flags.
UF_SETTABLE;
/// The file has the Windows `FILE_ATTRIBUTE_SPARSE_FILE` attribute.
#[cfg(any(target_os = "freebsd"))]
UF_SPARSE;
/// The file has the DOS, Windows and CIFS `FILE_ATTRIBUTE_SYSTEM`
/// attribute.
#[cfg(any(target_os = "freebsd"))]
UF_SYSTEM;
/// File renames and deletes are tracked.
#[cfg(any(target_os = "macos", target_os = "ios"))]
UF_TRACKED;
#[cfg(any(target_os = "dragonfly"))]
UF_XLINK;
}
}

/// Create a special or ordinary file, by pathname.
pub fn mknod<P: ?Sized + NixPath>(path: &P, kind: SFlag, perm: Mode, dev: dev_t) -> Result<()> {
let res = path.with_nix_path(|cstr| unsafe {
Expand Down
35 changes: 35 additions & 0 deletions src/unistd.rs
Expand Up @@ -6,6 +6,18 @@ use crate::errno::{self, Errno};
use crate::fcntl::{at_rawfd, AtFlags};
#[cfg(feature = "fs")]
use crate::fcntl::{fcntl, FcntlArg::F_SETFD, FdFlag, OFlag};
#[cfg(all(
feature = "fs",
any(
target_os = "openbsd",
target_os = "netbsd",
target_os = "freebsd",
target_os = "dragonfly",
target_os = "macos",
target_os = "ios"
)
))]
use crate::sys::stat::FileFlag;
#[cfg(feature = "fs")]
use crate::sys::stat::Mode;
use crate::{Error, NixPath, Result};
Expand Down Expand Up @@ -3275,3 +3287,26 @@ pub fn getpeereid(fd: RawFd) -> Result<(Uid, Gid)> {
Errno::result(ret).map(|_| (Uid(uid), Gid(gid)))
}
}

feature! {
#![all(feature = "fs")]

/// Set the file flags.
///
/// See also [chflags(2)](https://www.freebsd.org/cgi/man.cgi?query=chflags&sektion=2)
#[cfg(any(
target_os = "openbsd",
target_os = "netbsd",
target_os = "freebsd",
target_os = "dragonfly",
target_os = "macos",
target_os = "ios"
))]
pub fn chflags<P: ?Sized + NixPath>(path: &P, flags: FileFlag) -> Result<()> {
let res = path.with_nix_path(|cstr| unsafe {
libc::chflags(cstr.as_ptr(), flags.bits())
})?;

Errno::result(res).map(drop)
}
}
1 change: 1 addition & 0 deletions test/sys/mod.rs
Expand Up @@ -29,6 +29,7 @@ mod test_signalfd;
mod test_socket;
#[cfg(not(any(target_os = "redox")))]
mod test_sockopt;
mod test_stat;
#[cfg(any(target_os = "android", target_os = "linux"))]
mod test_sysinfo;
#[cfg(not(any(
Expand Down
27 changes: 27 additions & 0 deletions test/sys/test_stat.rs
@@ -0,0 +1,27 @@
#[cfg(target_os = "freebsd")]
#[test]
fn test_chflags() {
use nix::{
sys::stat::{fstat, FileFlag},
unistd::chflags,
};
use std::os::unix::io::AsRawFd;
use tempfile::NamedTempFile;

let f = NamedTempFile::new().unwrap();

let initial = FileFlag::from_bits_truncate(
fstat(f.as_raw_fd()).unwrap().st_flags.into(),
);
// UF_OFFLINE is preserved by all FreeBSD file systems, but not interpreted
// in any way, so it's handy for testing.
let commanded = initial ^ FileFlag::UF_OFFLINE;

chflags(f.path(), commanded).unwrap();

let changed = FileFlag::from_bits_truncate(
fstat(f.as_raw_fd()).unwrap().st_flags.into(),
);

assert_eq!(commanded, changed);
}

0 comments on commit fc16951

Please sign in to comment.