| 1 | //! POSIX-style `*at` functions. |
| 2 | //! |
| 3 | //! The `dirfd` argument to these functions may be a file descriptor for a |
| 4 | //! directory, the special value [`CWD`], or the special value [`ABS`]. |
| 5 | //! |
| 6 | //! [`CWD`]: crate::fs::CWD |
| 7 | //! [`ABS`]: crate::fs::ABS |
| 8 | |
| 9 | #![allow (unsafe_code)] |
| 10 | |
| 11 | use crate::buffer::Buffer; |
| 12 | use crate::fd::OwnedFd; |
| 13 | #[cfg (not(any(target_os = "espidf" , target_os = "horizon" , target_os = "vita" )))] |
| 14 | use crate::fs::Access; |
| 15 | #[cfg (not(target_os = "espidf" ))] |
| 16 | use crate::fs::AtFlags; |
| 17 | #[cfg (apple)] |
| 18 | use crate::fs::CloneFlags; |
| 19 | #[cfg (any(linux_kernel, apple))] |
| 20 | use crate::fs::RenameFlags; |
| 21 | #[cfg (not(target_os = "espidf" ))] |
| 22 | use crate::fs::Stat; |
| 23 | #[cfg (not(any(apple, target_os = "espidf" , target_os = "vita" , target_os = "wasi" )))] |
| 24 | use crate::fs::{Dev, FileType}; |
| 25 | #[cfg (not(any(target_os = "espidf" , target_os = "wasi" )))] |
| 26 | use crate::fs::{Gid, Uid}; |
| 27 | use crate::fs::{Mode, OFlags}; |
| 28 | use crate::{backend, io, path}; |
| 29 | use backend::fd::AsFd; |
| 30 | #[cfg (feature = "alloc" )] |
| 31 | use { |
| 32 | crate::ffi::{CStr, CString}, |
| 33 | crate::path::SMALL_PATH_BUFFER_SIZE, |
| 34 | alloc::vec::Vec, |
| 35 | backend::fd::BorrowedFd, |
| 36 | }; |
| 37 | #[cfg (not(any(target_os = "espidf" , target_os = "vita" )))] |
| 38 | use {crate::fs::Timestamps, crate::timespec::Nsecs}; |
| 39 | |
| 40 | /// `UTIME_NOW` for use with [`utimensat`]. |
| 41 | /// |
| 42 | /// [`utimensat`]: crate::fs::utimensat |
| 43 | #[cfg (not(any( |
| 44 | target_os = "espidf" , |
| 45 | target_os = "horizon" , |
| 46 | target_os = "redox" , |
| 47 | target_os = "vita" |
| 48 | )))] |
| 49 | pub const UTIME_NOW: Nsecs = backend::c::UTIME_NOW as Nsecs; |
| 50 | |
| 51 | /// `UTIME_OMIT` for use with [`utimensat`]. |
| 52 | /// |
| 53 | /// [`utimensat`]: crate::fs::utimensat |
| 54 | #[cfg (not(any( |
| 55 | target_os = "espidf" , |
| 56 | target_os = "horizon" , |
| 57 | target_os = "redox" , |
| 58 | target_os = "vita" |
| 59 | )))] |
| 60 | pub const UTIME_OMIT: Nsecs = backend::c::UTIME_OMIT as Nsecs; |
| 61 | |
| 62 | /// `openat(dirfd, path, oflags, mode)`—Opens a file. |
| 63 | /// |
| 64 | /// POSIX guarantees that `openat` will use the lowest unused file descriptor, |
| 65 | /// however it is not safe in general to rely on this, as file descriptors may |
| 66 | /// be unexpectedly allocated on other threads or in libraries. |
| 67 | /// |
| 68 | /// The `Mode` argument is only significant when creating a file. |
| 69 | /// |
| 70 | /// # References |
| 71 | /// - [POSIX] |
| 72 | /// - [Linux] |
| 73 | /// |
| 74 | /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/openat.html |
| 75 | /// [Linux]: https://man7.org/linux/man-pages/man2/openat.2.html |
| 76 | #[inline ] |
| 77 | pub fn openat<P: path::Arg, Fd: AsFd>( |
| 78 | dirfd: Fd, |
| 79 | path: P, |
| 80 | oflags: OFlags, |
| 81 | create_mode: Mode, |
| 82 | ) -> io::Result<OwnedFd> { |
| 83 | path.into_with_c_str(|path: &CStr| { |
| 84 | backend::fs::syscalls::openat(dirfd.as_fd(), path, flags:oflags, create_mode) |
| 85 | }) |
| 86 | } |
| 87 | |
| 88 | /// `readlinkat(fd, path)`—Reads the contents of a symlink. |
| 89 | /// |
| 90 | /// If `reuse` already has available capacity, reuse it if possible. |
| 91 | /// |
| 92 | /// # References |
| 93 | /// - [POSIX] |
| 94 | /// - [Linux] |
| 95 | /// |
| 96 | /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/readlinkat.html |
| 97 | /// [Linux]: https://man7.org/linux/man-pages/man2/readlinkat.2.html |
| 98 | #[cfg (feature = "alloc" )] |
| 99 | #[cfg_attr (docsrs, doc(cfg(feature = "alloc" )))] |
| 100 | #[inline ] |
| 101 | pub fn readlinkat<P: path::Arg, Fd: AsFd, B: Into<Vec<u8>>>( |
| 102 | dirfd: Fd, |
| 103 | path: P, |
| 104 | reuse: B, |
| 105 | ) -> io::Result<CString> { |
| 106 | path.into_with_c_str(|path: &CStr| _readlinkat(dirfd.as_fd(), path, buffer:reuse.into())) |
| 107 | } |
| 108 | |
| 109 | #[cfg (feature = "alloc" )] |
| 110 | #[allow (unsafe_code)] |
| 111 | fn _readlinkat(dirfd: BorrowedFd<'_>, path: &CStr, mut buffer: Vec<u8>) -> io::Result<CString> { |
| 112 | buffer.clear(); |
| 113 | buffer.reserve(SMALL_PATH_BUFFER_SIZE); |
| 114 | |
| 115 | loop { |
| 116 | let buf = buffer.spare_capacity_mut(); |
| 117 | |
| 118 | // SAFETY: `readlinkat` behaves. |
| 119 | let nread = unsafe { |
| 120 | backend::fs::syscalls::readlinkat( |
| 121 | dirfd.as_fd(), |
| 122 | path, |
| 123 | (buf.as_mut_ptr().cast(), buf.len()), |
| 124 | )? |
| 125 | }; |
| 126 | |
| 127 | debug_assert!(nread <= buffer.capacity()); |
| 128 | if nread < buffer.capacity() { |
| 129 | // SAFETY: From the [documentation]: “On success, these calls |
| 130 | // return the number of bytes placed in buf.” |
| 131 | // |
| 132 | // [documentation]: https://man7.org/linux/man-pages/man2/readlinkat.2.html |
| 133 | unsafe { |
| 134 | buffer.set_len(nread); |
| 135 | } |
| 136 | |
| 137 | // SAFETY: |
| 138 | // - “readlink places the contents of the symbolic link pathname |
| 139 | // in the buffer buf” |
| 140 | // - [POSIX definition 3.271: Pathname]: “A string that is used |
| 141 | // to identify a file.” |
| 142 | // - [POSIX definition 3.375: String]: “A contiguous sequence of |
| 143 | // bytes terminated by and including the first null byte.” |
| 144 | // - “readlink does not append a terminating null byte to buf.” |
| 145 | // |
| 146 | // Thus, there will be no NUL bytes in the string. |
| 147 | // |
| 148 | // [POSIX definition 3.271: Pathname]: https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/V1_chap03.html#tag_03_271 |
| 149 | // [POSIX definition 3.375: String]: https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/V1_chap03.html#tag_03_375 |
| 150 | unsafe { |
| 151 | return Ok(CString::from_vec_unchecked(buffer)); |
| 152 | } |
| 153 | } |
| 154 | |
| 155 | // Use `Vec` reallocation strategy to grow capacity exponentially. |
| 156 | buffer.reserve(buffer.capacity() + 1); |
| 157 | } |
| 158 | } |
| 159 | |
| 160 | /// `readlinkat(fd, path)`—Reads the contents of a symlink, without |
| 161 | /// allocating. |
| 162 | /// |
| 163 | /// This is the "raw" version which avoids allocating, but which truncates the |
| 164 | /// string if it doesn't fit in the provided buffer, and doesn't NUL-terminate |
| 165 | /// the string. |
| 166 | /// |
| 167 | /// # References |
| 168 | /// - [POSIX] |
| 169 | /// - [Linux] |
| 170 | /// |
| 171 | /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/readlinkat.html |
| 172 | /// [Linux]: https://man7.org/linux/man-pages/man2/readlinkat.2.html |
| 173 | #[inline ] |
| 174 | pub fn readlinkat_raw<P: path::Arg, Fd: AsFd, Buf: Buffer<u8>>( |
| 175 | dirfd: Fd, |
| 176 | path: P, |
| 177 | mut buf: Buf, |
| 178 | ) -> io::Result<Buf::Output> { |
| 179 | // SAFETY: `readlinkat` behaves. |
| 180 | let len: usize = path.into_with_c_str(|path: &CStr| unsafe { |
| 181 | backend::fs::syscalls::readlinkat(dirfd.as_fd(), path, buf.parts_mut()) |
| 182 | })?; |
| 183 | // SAFETY: `readlinkat` behaves. |
| 184 | unsafe { Ok(buf.assume_init(len)) } |
| 185 | } |
| 186 | |
| 187 | /// `mkdirat(fd, path, mode)`—Creates a directory. |
| 188 | /// |
| 189 | /// # References |
| 190 | /// - [POSIX] |
| 191 | /// - [Linux] |
| 192 | /// |
| 193 | /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/mkdirat.html |
| 194 | /// [Linux]: https://man7.org/linux/man-pages/man2/mkdirat.2.html |
| 195 | #[inline ] |
| 196 | pub fn mkdirat<P: path::Arg, Fd: AsFd>(dirfd: Fd, path: P, mode: Mode) -> io::Result<()> { |
| 197 | path.into_with_c_str(|path: &CStr| backend::fs::syscalls::mkdirat(dirfd.as_fd(), path, mode)) |
| 198 | } |
| 199 | |
| 200 | /// `linkat(old_dirfd, old_path, new_dirfd, new_path, flags)`—Creates a hard |
| 201 | /// link. |
| 202 | /// |
| 203 | /// # References |
| 204 | /// - [POSIX] |
| 205 | /// - [Linux] |
| 206 | /// |
| 207 | /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/linkat.html |
| 208 | /// [Linux]: https://man7.org/linux/man-pages/man2/linkat.2.html |
| 209 | #[cfg (not(target_os = "espidf" ))] |
| 210 | #[inline ] |
| 211 | pub fn linkat<P: path::Arg, Q: path::Arg, PFd: AsFd, QFd: AsFd>( |
| 212 | old_dirfd: PFd, |
| 213 | old_path: P, |
| 214 | new_dirfd: QFd, |
| 215 | new_path: Q, |
| 216 | flags: AtFlags, |
| 217 | ) -> io::Result<()> { |
| 218 | old_path.into_with_c_str(|old_path: &CStr| { |
| 219 | new_path.into_with_c_str(|new_path: &CStr| { |
| 220 | backend::fs::syscalls::linkat( |
| 221 | old_dirfd.as_fd(), |
| 222 | old_path, |
| 223 | new_dirfd.as_fd(), |
| 224 | new_path, |
| 225 | flags, |
| 226 | ) |
| 227 | }) |
| 228 | }) |
| 229 | } |
| 230 | |
| 231 | /// `unlinkat(fd, path, flags)`—Unlinks a file or remove a directory. |
| 232 | /// |
| 233 | /// With the [`REMOVEDIR`] flag, this removes a directory. This is in place of |
| 234 | /// a `rmdirat` function. |
| 235 | /// |
| 236 | /// # References |
| 237 | /// - [POSIX] |
| 238 | /// - [Linux] |
| 239 | /// |
| 240 | /// [`REMOVEDIR`]: AtFlags::REMOVEDIR |
| 241 | /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/unlinkat.html |
| 242 | /// [Linux]: https://man7.org/linux/man-pages/man2/unlinkat.2.html |
| 243 | #[cfg (not(target_os = "espidf" ))] |
| 244 | #[inline ] |
| 245 | pub fn unlinkat<P: path::Arg, Fd: AsFd>(dirfd: Fd, path: P, flags: AtFlags) -> io::Result<()> { |
| 246 | path.into_with_c_str(|path: &CStr| backend::fs::syscalls::unlinkat(dirfd.as_fd(), path, flags)) |
| 247 | } |
| 248 | |
| 249 | /// `renameat(old_dirfd, old_path, new_dirfd, new_path)`—Renames a file or |
| 250 | /// directory. |
| 251 | /// |
| 252 | /// See [`renameat_with`] to pass additional flags. |
| 253 | /// |
| 254 | /// # References |
| 255 | /// - [POSIX] |
| 256 | /// - [Linux] |
| 257 | /// |
| 258 | /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/renameat.html |
| 259 | /// [Linux]: https://man7.org/linux/man-pages/man2/renameat.2.html |
| 260 | #[inline ] |
| 261 | pub fn renameat<P: path::Arg, Q: path::Arg, PFd: AsFd, QFd: AsFd>( |
| 262 | old_dirfd: PFd, |
| 263 | old_path: P, |
| 264 | new_dirfd: QFd, |
| 265 | new_path: Q, |
| 266 | ) -> io::Result<()> { |
| 267 | old_path.into_with_c_str(|old_path: &CStr| { |
| 268 | new_path.into_with_c_str(|new_path: &CStr| { |
| 269 | backend::fs::syscalls::renameat( |
| 270 | old_dirfd.as_fd(), |
| 271 | old_path, |
| 272 | new_dirfd.as_fd(), |
| 273 | new_path, |
| 274 | ) |
| 275 | }) |
| 276 | }) |
| 277 | } |
| 278 | |
| 279 | /// `renameat2(old_dirfd, old_path, new_dirfd, new_path, flags)`—Renames a |
| 280 | /// file or directory. |
| 281 | /// |
| 282 | /// `renameat_with` is the same as [`renameat`] but adds an additional |
| 283 | /// flags operand. |
| 284 | /// |
| 285 | /// # References |
| 286 | /// - [Linux] |
| 287 | /// |
| 288 | /// [Linux]: https://man7.org/linux/man-pages/man2/renameat2.2.html |
| 289 | #[cfg (any(apple, linux_kernel))] |
| 290 | #[inline ] |
| 291 | #[doc (alias = "renameat2" )] |
| 292 | #[doc (alias = "renameatx_np" )] |
| 293 | pub fn renameat_with<P: path::Arg, Q: path::Arg, PFd: AsFd, QFd: AsFd>( |
| 294 | old_dirfd: PFd, |
| 295 | old_path: P, |
| 296 | new_dirfd: QFd, |
| 297 | new_path: Q, |
| 298 | flags: RenameFlags, |
| 299 | ) -> io::Result<()> { |
| 300 | old_path.into_with_c_str(|old_path: &CStr| { |
| 301 | new_path.into_with_c_str(|new_path: &CStr| { |
| 302 | backend::fs::syscalls::renameat2( |
| 303 | old_dirfd.as_fd(), |
| 304 | old_path, |
| 305 | new_dirfd.as_fd(), |
| 306 | new_path, |
| 307 | flags, |
| 308 | ) |
| 309 | }) |
| 310 | }) |
| 311 | } |
| 312 | |
| 313 | /// `symlinkat(old_path, new_dirfd, new_path)`—Creates a symlink. |
| 314 | /// |
| 315 | /// # References |
| 316 | /// - [POSIX] |
| 317 | /// - [Linux] |
| 318 | /// |
| 319 | /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/symlinkat.html |
| 320 | /// [Linux]: https://man7.org/linux/man-pages/man2/symlinkat.2.html |
| 321 | #[inline ] |
| 322 | pub fn symlinkat<P: path::Arg, Q: path::Arg, Fd: AsFd>( |
| 323 | old_path: P, |
| 324 | new_dirfd: Fd, |
| 325 | new_path: Q, |
| 326 | ) -> io::Result<()> { |
| 327 | old_path.into_with_c_str(|old_path: &CStr| { |
| 328 | new_path.into_with_c_str(|new_path: &CStr| { |
| 329 | backend::fs::syscalls::symlinkat(old_path, dirfd:new_dirfd.as_fd(), new_path) |
| 330 | }) |
| 331 | }) |
| 332 | } |
| 333 | |
| 334 | /// `fstatat(dirfd, path, flags)`—Queries metadata for a file or directory. |
| 335 | /// |
| 336 | /// [`Mode::from_raw_mode`] and [`FileType::from_raw_mode`] may be used to |
| 337 | /// interpret the `st_mode` field. |
| 338 | /// |
| 339 | /// # References |
| 340 | /// - [POSIX] |
| 341 | /// - [Linux] |
| 342 | /// |
| 343 | /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/fstatat.html |
| 344 | /// [Linux]: https://man7.org/linux/man-pages/man2/fstatat.2.html |
| 345 | /// [`Mode::from_raw_mode`]: crate::fs::Mode::from_raw_mode |
| 346 | /// [`FileType::from_raw_mode`]: crate::fs::FileType::from_raw_mode |
| 347 | #[cfg (not(target_os = "espidf" ))] |
| 348 | #[inline ] |
| 349 | #[doc (alias = "fstatat" )] |
| 350 | pub fn statat<P: path::Arg, Fd: AsFd>(dirfd: Fd, path: P, flags: AtFlags) -> io::Result<Stat> { |
| 351 | path.into_with_c_str(|path: &CStr| backend::fs::syscalls::statat(dirfd.as_fd(), path, flags)) |
| 352 | } |
| 353 | |
| 354 | /// `faccessat(dirfd, path, access, flags)`—Tests permissions for a file or |
| 355 | /// directory. |
| 356 | /// |
| 357 | /// On Linux before 5.8, this function uses the `faccessat` system call which |
| 358 | /// doesn't support any flags. This function emulates support for the |
| 359 | /// [`AtFlags::EACCESS`] flag by checking whether the uid and gid of the |
| 360 | /// process match the effective uid and gid, in which case the `EACCESS` flag |
| 361 | /// can be ignored. In Linux 5.8 and beyond `faccessat2` is used, which |
| 362 | /// supports flags. |
| 363 | /// |
| 364 | /// # References |
| 365 | /// - [POSIX] |
| 366 | /// - [Linux] |
| 367 | /// |
| 368 | /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/faccessat.html |
| 369 | /// [Linux]: https://man7.org/linux/man-pages/man2/faccessat.2.html |
| 370 | #[cfg (not(any(target_os = "espidf" , target_os = "horizon" , target_os = "vita" )))] |
| 371 | #[inline ] |
| 372 | #[doc (alias = "faccessat" )] |
| 373 | pub fn accessat<P: path::Arg, Fd: AsFd>( |
| 374 | dirfd: Fd, |
| 375 | path: P, |
| 376 | access: Access, |
| 377 | flags: AtFlags, |
| 378 | ) -> io::Result<()> { |
| 379 | path.into_with_c_str(|path: &CStr| backend::fs::syscalls::accessat(dirfd.as_fd(), path, access, flags)) |
| 380 | } |
| 381 | |
| 382 | /// `utimensat(dirfd, path, times, flags)`—Sets file or directory timestamps. |
| 383 | /// |
| 384 | /// # References |
| 385 | /// - [POSIX] |
| 386 | /// - [Linux] |
| 387 | /// |
| 388 | /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/utimensat.html |
| 389 | /// [Linux]: https://man7.org/linux/man-pages/man2/utimensat.2.html |
| 390 | #[cfg (not(any(target_os = "espidf" , target_os = "horizon" , target_os = "vita" )))] |
| 391 | #[inline ] |
| 392 | pub fn utimensat<P: path::Arg, Fd: AsFd>( |
| 393 | dirfd: Fd, |
| 394 | path: P, |
| 395 | times: &Timestamps, |
| 396 | flags: AtFlags, |
| 397 | ) -> io::Result<()> { |
| 398 | path.into_with_c_str(|path: &CStr| backend::fs::syscalls::utimensat(dirfd.as_fd(), path, times, flags)) |
| 399 | } |
| 400 | |
| 401 | /// `fchmodat(dirfd, path, mode, flags)`—Sets file or directory permissions. |
| 402 | /// |
| 403 | /// Platform support for flags varies widely, for example on Linux |
| 404 | /// [`AtFlags::SYMLINK_NOFOLLOW`] is not implemented and therefore |
| 405 | /// [`io::Errno::OPNOTSUPP`] will be returned. |
| 406 | /// |
| 407 | /// # References |
| 408 | /// - [POSIX] |
| 409 | /// - [Linux] |
| 410 | /// |
| 411 | /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/fchmodat.html |
| 412 | /// [Linux]: https://man7.org/linux/man-pages/man2/fchmodat.2.html |
| 413 | #[cfg (not(any(target_os = "espidf" , target_os = "wasi" )))] |
| 414 | #[inline ] |
| 415 | #[doc (alias = "fchmodat" )] |
| 416 | pub fn chmodat<P: path::Arg, Fd: AsFd>( |
| 417 | dirfd: Fd, |
| 418 | path: P, |
| 419 | mode: Mode, |
| 420 | flags: AtFlags, |
| 421 | ) -> io::Result<()> { |
| 422 | path.into_with_c_str(|path: &CStr| backend::fs::syscalls::chmodat(dirfd.as_fd(), path, mode, flags)) |
| 423 | } |
| 424 | |
| 425 | /// `fclonefileat(src, dst_dir, dst, flags)`—Efficiently copies between files. |
| 426 | /// |
| 427 | /// # References |
| 428 | /// - [Apple] |
| 429 | /// |
| 430 | /// [Apple]: https://github.com/apple-oss-distributions/xnu/blob/main/bsd/man/man2/clonefile.2 |
| 431 | #[cfg (apple)] |
| 432 | #[inline ] |
| 433 | pub fn fclonefileat<Fd: AsFd, DstFd: AsFd, P: path::Arg>( |
| 434 | src: Fd, |
| 435 | dst_dir: DstFd, |
| 436 | dst: P, |
| 437 | flags: CloneFlags, |
| 438 | ) -> io::Result<()> { |
| 439 | dst.into_with_c_str(|dst| { |
| 440 | backend::fs::syscalls::fclonefileat(src.as_fd(), dst_dir.as_fd(), dst, flags) |
| 441 | }) |
| 442 | } |
| 443 | |
| 444 | /// `mknodat(dirfd, path, mode, dev)`—Creates special or normal files. |
| 445 | /// |
| 446 | /// # References |
| 447 | /// - [POSIX] |
| 448 | /// - [Linux] |
| 449 | /// |
| 450 | /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/mknodat.html |
| 451 | /// [Linux]: https://man7.org/linux/man-pages/man2/mknodat.2.html |
| 452 | #[cfg (not(any( |
| 453 | apple, |
| 454 | target_os = "espidf" , |
| 455 | target_os = "horizon" , |
| 456 | target_os = "vita" , |
| 457 | target_os = "wasi" |
| 458 | )))] |
| 459 | #[inline ] |
| 460 | pub fn mknodat<P: path::Arg, Fd: AsFd>( |
| 461 | dirfd: Fd, |
| 462 | path: P, |
| 463 | file_type: FileType, |
| 464 | mode: Mode, |
| 465 | dev: Dev, |
| 466 | ) -> io::Result<()> { |
| 467 | path.into_with_c_str(|path: &CStr| { |
| 468 | backend::fs::syscalls::mknodat(dirfd.as_fd(), path, file_type, mode, dev) |
| 469 | }) |
| 470 | } |
| 471 | |
| 472 | /// `fchownat(dirfd, path, owner, group, flags)`—Sets file or directory |
| 473 | /// ownership. |
| 474 | /// |
| 475 | /// # References |
| 476 | /// - [POSIX] |
| 477 | /// - [Linux] |
| 478 | /// |
| 479 | /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/fchownat.html |
| 480 | /// [Linux]: https://man7.org/linux/man-pages/man2/fchownat.2.html |
| 481 | #[cfg (not(any(target_os = "espidf" , target_os = "wasi" )))] |
| 482 | #[inline ] |
| 483 | #[doc (alias = "fchownat" )] |
| 484 | pub fn chownat<P: path::Arg, Fd: AsFd>( |
| 485 | dirfd: Fd, |
| 486 | path: P, |
| 487 | owner: Option<Uid>, |
| 488 | group: Option<Gid>, |
| 489 | flags: AtFlags, |
| 490 | ) -> io::Result<()> { |
| 491 | path.into_with_c_str(|path: &CStr| { |
| 492 | backend::fs::syscalls::chownat(dirfd.as_fd(), path, owner, group, flags) |
| 493 | }) |
| 494 | } |
| 495 | |