| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683 |
- //===----------------------------------------------------------------------===//
- //
- // This source file is part of the Swift System open source project
- //
- // Copyright (c) 2025 - 2026 Apple Inc. and the Swift System project authors
- // Licensed under Apache License v2.0 with Runtime Library Exception
- //
- // See https://swift.org/LICENSE.txt for license information
- //
- //===----------------------------------------------------------------------===//
- #if !os(Windows)
- // Must import here to use C stat properties in @_alwaysEmitIntoClient APIs.
- #if SYSTEM_PACKAGE_DARWIN
- import Darwin
- #elseif canImport(Glibc)
- import CSystem
- import Glibc
- #elseif canImport(Musl)
- import CSystem
- import Musl
- #elseif canImport(WASILibc)
- import WASILibc
- #elseif canImport(Android)
- import CSystem
- import Android
- #else
- #error("Unsupported Platform")
- #endif
- // MARK: - Stat
- /// A Swift wrapper of the C `stat` struct.
- ///
- /// - Note: Only available on Unix-like platforms.
- @frozen
- @available(System 1.7.0, *)
- public struct Stat: RawRepresentable, Sendable {
- /// The raw C `stat` struct.
- @_alwaysEmitIntoClient
- public var rawValue: CInterop.Stat
- /// Creates a Swift `Stat` from the raw C struct.
- @_alwaysEmitIntoClient
- public init(rawValue: CInterop.Stat) { self.rawValue = rawValue }
- // MARK: Stat.Flags
- /// Flags representing those passed to `fstatat()`.
- @frozen
- public struct Flags: OptionSet, Sendable, Hashable, Codable {
- /// The raw C flags.
- @_alwaysEmitIntoClient
- public let rawValue: CInt
- /// Creates a strongly-typed `Stat.Flags` from raw C flags.
- @_alwaysEmitIntoClient
- public init(rawValue: CInt) { self.rawValue = rawValue }
- /// If the path ends with a symbolic link, return information about the link itself.
- ///
- /// The corresponding C constant is `AT_SYMLINK_NOFOLLOW`.
- @_alwaysEmitIntoClient
- public static var symlinkNoFollow: Flags { Flags(rawValue: _AT_SYMLINK_NOFOLLOW) }
- #if SYSTEM_PACKAGE_DARWIN
- /// If the path ends with a symbolic link, return information about the link itself.
- /// If _any_ symbolic link is encountered during path resolution, return an error.
- ///
- /// The corresponding C constant is `AT_SYMLINK_NOFOLLOW_ANY`.
- /// - Note: Only available on Darwin.
- @_alwaysEmitIntoClient
- public static var symlinkNoFollowAny: Flags { Flags(rawValue: _AT_SYMLINK_NOFOLLOW_ANY) }
- #endif
- #if canImport(Darwin, _version: 346) || os(FreeBSD)
- /// If the path does not reside in the hierarchy beneath the starting directory, return an error.
- ///
- /// The corresponding C constant is `AT_RESOLVE_BENEATH`.
- /// - Note: Only available on Darwin and FreeBSD.
- @_alwaysEmitIntoClient
- public static var resolveBeneath: Flags { Flags(rawValue: _AT_RESOLVE_BENEATH) }
- #endif
- }
- // MARK: Initializers
- /// Creates a `Stat` struct from a `FilePath`.
- ///
- /// `followTargetSymlink` determines the behavior if `path` ends with a symbolic link.
- /// By default, `followTargetSymlink` is `true` and this initializer behaves like `stat()`.
- /// If `followTargetSymlink` is set to `false`, this initializer behaves like `lstat()` and
- /// returns information about the symlink itself.
- ///
- /// The corresponding C function is `stat()` or `lstat()` as described above.
- @_alwaysEmitIntoClient
- public init(
- _ path: FilePath,
- followTargetSymlink: Bool = true,
- retryOnInterrupt: Bool = true
- ) throws(Errno) {
- self.rawValue = try path.withPlatformString {
- Self._stat(
- $0,
- followTargetSymlink: followTargetSymlink,
- retryOnInterrupt: retryOnInterrupt
- )
- }.get()
- }
- /// Creates a `Stat` struct from an `UnsafePointer<CChar>` path.
- ///
- /// `followTargetSymlink` determines the behavior if `path` ends with a symbolic link.
- /// By default, `followTargetSymlink` is `true` and this initializer behaves like `stat()`.
- /// If `followTargetSymlink` is set to `false`, this initializer behaves like `lstat()` and
- /// returns information about the symlink itself.
- ///
- /// The corresponding C function is `stat()` or `lstat()` as described above.
- @_alwaysEmitIntoClient
- public init(
- _ path: UnsafePointer<CChar>,
- followTargetSymlink: Bool = true,
- retryOnInterrupt: Bool = true
- ) throws(Errno) {
- self.rawValue = try Self._stat(
- path,
- followTargetSymlink: followTargetSymlink,
- retryOnInterrupt: retryOnInterrupt
- ).get()
- }
- @usableFromInline
- internal static func _stat(
- _ ptr: UnsafePointer<CChar>,
- followTargetSymlink: Bool,
- retryOnInterrupt: Bool
- ) -> Result<CInterop.Stat, Errno> {
- var result = CInterop.Stat()
- return nothingOrErrno(retryOnInterrupt: retryOnInterrupt) {
- if followTargetSymlink {
- system_stat(ptr, &result)
- } else {
- system_lstat(ptr, &result)
- }
- }.map { result }
- }
- /// Creates a `Stat` struct from a `FileDescriptor`.
- ///
- /// The corresponding C function is `fstat()`.
- @_alwaysEmitIntoClient
- public init(
- _ fd: FileDescriptor,
- retryOnInterrupt: Bool = true
- ) throws(Errno) {
- self.rawValue = try Self._fstat(
- fd,
- retryOnInterrupt: retryOnInterrupt
- ).get()
- }
- @usableFromInline
- internal static func _fstat(
- _ fd: FileDescriptor,
- retryOnInterrupt: Bool
- ) -> Result<CInterop.Stat, Errno> {
- var result = CInterop.Stat()
- return nothingOrErrno(retryOnInterrupt: retryOnInterrupt) {
- system_fstat(fd.rawValue, &result)
- }.map { result }
- }
- /// Creates a `Stat` struct from a `FilePath` and `Flags`.
- ///
- /// If `path` is relative, it is resolved against the current working directory.
- ///
- /// The corresponding C function is `fstatat()`.
- @_alwaysEmitIntoClient
- public init(
- _ path: FilePath,
- flags: Stat.Flags,
- retryOnInterrupt: Bool = true
- ) throws(Errno) {
- self.rawValue = try path.withPlatformString {
- Self._fstatat(
- $0,
- relativeTo: _AT_FDCWD,
- flags: flags,
- retryOnInterrupt: retryOnInterrupt
- )
- }.get()
- }
- /// Creates a `Stat` struct from a `FilePath` and `Flags`,
- /// including a `FileDescriptor` to resolve a relative path.
- ///
- /// If `path` is absolute (starts with a forward slash), then `fd` is ignored.
- /// If `path` is relative, it is resolved against the directory given by `fd`.
- ///
- /// The corresponding C function is `fstatat()`.
- @_alwaysEmitIntoClient
- public init(
- _ path: FilePath,
- relativeTo fd: FileDescriptor,
- flags: Stat.Flags,
- retryOnInterrupt: Bool = true
- ) throws(Errno) {
- self.rawValue = try path.withPlatformString {
- Self._fstatat(
- $0,
- relativeTo: fd.rawValue,
- flags: flags,
- retryOnInterrupt: retryOnInterrupt
- )
- }.get()
- }
- /// Creates a `Stat` struct from an `UnsafePointer<CChar>` path and `Flags`.
- ///
- /// If `path` is relative, it is resolved against the current working directory.
- ///
- /// The corresponding C function is `fstatat()`.
- @_alwaysEmitIntoClient
- public init(
- _ path: UnsafePointer<CChar>,
- flags: Stat.Flags,
- retryOnInterrupt: Bool = true
- ) throws(Errno) {
- self.rawValue = try Self._fstatat(
- path,
- relativeTo: _AT_FDCWD,
- flags: flags,
- retryOnInterrupt: retryOnInterrupt
- ).get()
- }
- /// Creates a `Stat` struct from an `UnsafePointer<CChar>` path and `Flags`,
- /// including a `FileDescriptor` to resolve a relative path.
- ///
- /// If `path` is absolute (starts with a forward slash), then `fd` is ignored.
- /// If `path` is relative, it is resolved against the directory given by `fd`.
- ///
- /// The corresponding C function is `fstatat()`.
- @_alwaysEmitIntoClient
- public init(
- _ path: UnsafePointer<CChar>,
- relativeTo fd: FileDescriptor,
- flags: Stat.Flags,
- retryOnInterrupt: Bool = true
- ) throws(Errno) {
- self.rawValue = try Self._fstatat(
- path,
- relativeTo: fd.rawValue,
- flags: flags,
- retryOnInterrupt: retryOnInterrupt
- ).get()
- }
- @usableFromInline
- internal static func _fstatat(
- _ path: UnsafePointer<CChar>,
- relativeTo fd: FileDescriptor.RawValue,
- flags: Stat.Flags,
- retryOnInterrupt: Bool
- ) -> Result<CInterop.Stat, Errno> {
- var result = CInterop.Stat()
- return nothingOrErrno(retryOnInterrupt: retryOnInterrupt) {
- system_fstatat(fd, path, &result, flags.rawValue)
- }.map { result }
- }
- // MARK: Properties
- /// ID of device containing file
- ///
- /// The corresponding C property is `st_dev`.
- @_alwaysEmitIntoClient
- public var deviceID: DeviceID {
- get { DeviceID(rawValue: numericCast(rawValue.st_dev)) }
- set { rawValue.st_dev = numericCast(newValue.rawValue) }
- }
- /// Inode number
- ///
- /// The corresponding C property is `st_ino`.
- @_alwaysEmitIntoClient
- public var inode: Inode {
- get { Inode(rawValue: numericCast(rawValue.st_ino)) }
- set { rawValue.st_ino = numericCast(newValue.rawValue) }
- }
- /// File mode
- ///
- /// The corresponding C property is `st_mode`.
- @_alwaysEmitIntoClient
- public var mode: FileMode {
- get { FileMode(rawValue: numericCast(rawValue.st_mode)) }
- set { rawValue.st_mode = numericCast(newValue.rawValue) }
- }
- /// File type for the given mode
- ///
- /// - Note: This property is equivalent to `mode.type`. Modifying this
- /// property will update the underlying `st_mode` accordingly.
- @_alwaysEmitIntoClient
- public var type: FileType {
- get { mode.type }
- set {
- var newMode = mode
- newMode.type = newValue
- mode = newMode
- }
- }
- /// File permissions for the given mode
- ///
- /// - Note: This property is equivalent to `mode.permissions`. Modifying
- /// this property will update the underlying `st_mode` accordingly.
- @_alwaysEmitIntoClient
- public var permissions: FilePermissions {
- get { mode.permissions }
- set {
- var newMode = mode
- newMode.permissions = newValue
- mode = newMode
- }
- }
- /// Number of hard links
- ///
- /// The corresponding C property is `st_nlink`.
- @_alwaysEmitIntoClient
- public var linkCount: Int {
- get { Int(rawValue.st_nlink) }
- set { rawValue.st_nlink = numericCast(newValue) }
- }
- /// User ID of owner
- ///
- /// The corresponding C property is `st_uid`.
- @_alwaysEmitIntoClient
- public var userID: UserID {
- get { UserID(rawValue: rawValue.st_uid) }
- set { rawValue.st_uid = newValue.rawValue }
- }
- /// Group ID of owner
- ///
- /// The corresponding C property is `st_gid`.
- @_alwaysEmitIntoClient
- public var groupID: GroupID {
- get { GroupID(rawValue: rawValue.st_gid) }
- set { rawValue.st_gid = newValue.rawValue }
- }
- /// Device ID (if special file)
- ///
- /// For character or block special files, the returned `DeviceID` may have
- /// meaningful major and minor values. For non-special files, this
- /// property is usually meaningless and often set to 0.
- ///
- /// The corresponding C property is `st_rdev`.
- @_alwaysEmitIntoClient
- public var specialDeviceID: DeviceID {
- get { DeviceID(rawValue: numericCast(rawValue.st_rdev)) }
- set { rawValue.st_rdev = numericCast(newValue.rawValue) }
- }
- /// Total size, in bytes
- ///
- /// The semantics of this property are tied to the underlying C `st_size` field,
- /// which can have file-system–dependent behavior. For example, this property
- /// can return different values for a file's data fork and resource fork, and some
- /// file systems report logical size rather than actual disk usage for compressed
- /// or cloned files.
- ///
- /// The corresponding C property is `st_size`.
- @_alwaysEmitIntoClient
- public var size: Int64 {
- get { Int64(rawValue.st_size) }
- set { rawValue.st_size = numericCast(newValue) }
- }
- /// Block size for file system I/O, in bytes
- ///
- /// The corresponding C property is `st_blksize`.
- @_alwaysEmitIntoClient
- public var preferredIOBlockSize: Int {
- get { Int(rawValue.st_blksize) }
- set { rawValue.st_blksize = numericCast(newValue) }
- }
- /// Number of 512-byte blocks allocated
- ///
- /// The semantics of this property are tied to the underlying C `st_blocks` field,
- /// which can have file-system–dependent behavior.
- ///
- /// The corresponding C property is `st_blocks`.
- @_alwaysEmitIntoClient
- public var blocksAllocated: Int64 {
- get { Int64(rawValue.st_blocks) }
- set { rawValue.st_blocks = numericCast(newValue) }
- }
- /// Total size allocated, in bytes
- ///
- /// The semantics of this property are tied to the underlying C `st_blocks` field,
- /// which can have file-system–dependent behavior.
- ///
- /// - Note: Calculated as `512 * blocksAllocated`.
- @_alwaysEmitIntoClient
- public var sizeAllocated: Int64 {
- 512 * blocksAllocated
- }
- // NOTE: "st_" property names are used for the `timespec` properties so
- // we can reserve `accessTime`, `modificationTime`, etc. for potential
- // `UTCClock.Instant` properties in the future.
- /// Time of last access, given as a C `timespec` since the Epoch.
- ///
- /// The corresponding C property is `st_atim` (or `st_atimespec` on Darwin).
- @_alwaysEmitIntoClient
- public var st_atim: timespec {
- get {
- #if SYSTEM_PACKAGE_DARWIN
- rawValue.st_atimespec
- #else
- rawValue.st_atim
- #endif
- }
- set {
- #if SYSTEM_PACKAGE_DARWIN
- rawValue.st_atimespec = newValue
- #else
- rawValue.st_atim = newValue
- #endif
- }
- }
- /// Time of last modification, given as a C `timespec` since the Epoch.
- ///
- /// The corresponding C property is `st_mtim` (or `st_mtimespec` on Darwin).
- @_alwaysEmitIntoClient
- public var st_mtim: timespec {
- get {
- #if SYSTEM_PACKAGE_DARWIN
- rawValue.st_mtimespec
- #else
- rawValue.st_mtim
- #endif
- }
- set {
- #if SYSTEM_PACKAGE_DARWIN
- rawValue.st_mtimespec = newValue
- #else
- rawValue.st_mtim = newValue
- #endif
- }
- }
- /// Time of last status (inode) change, given as a C `timespec` since the Epoch.
- ///
- /// The corresponding C property is `st_ctim` (or `st_ctimespec` on Darwin).
- @_alwaysEmitIntoClient
- public var st_ctim: timespec {
- get {
- #if SYSTEM_PACKAGE_DARWIN
- rawValue.st_ctimespec
- #else
- rawValue.st_ctim
- #endif
- }
- set {
- #if SYSTEM_PACKAGE_DARWIN
- rawValue.st_ctimespec = newValue
- #else
- rawValue.st_ctim = newValue
- #endif
- }
- }
- #if SYSTEM_PACKAGE_DARWIN || os(FreeBSD)
- /// Time of file creation, given as a C `timespec` since the Epoch.
- ///
- /// The corresponding C property is `st_birthtim` (or `st_birthtimespec` on Darwin).
- /// - Note: Only available on Darwin and FreeBSD.
- @_alwaysEmitIntoClient
- public var st_birthtim: timespec {
- get {
- #if SYSTEM_PACKAGE_DARWIN
- rawValue.st_birthtimespec
- #else
- rawValue.st_birthtim
- #endif
- }
- set {
- #if SYSTEM_PACKAGE_DARWIN
- rawValue.st_birthtimespec = newValue
- #else
- rawValue.st_birthtim = newValue
- #endif
- }
- }
- #endif
- #if SYSTEM_PACKAGE_DARWIN || os(FreeBSD) || os(OpenBSD)
- /// File flags
- ///
- /// The corresponding C property is `st_flags`.
- /// - Note: Only available on Darwin, FreeBSD, and OpenBSD.
- @_alwaysEmitIntoClient
- public var flags: FileFlags {
- get { FileFlags(rawValue: rawValue.st_flags) }
- set { rawValue.st_flags = newValue.rawValue }
- }
- /// File generation number
- ///
- /// The file generation number may be used to distinguish between different
- /// files that have used the same inode over time.
- ///
- /// The corresponding C property is `st_gen`.
- /// - Note: Only available on Darwin, FreeBSD, and OpenBSD. The underlying C
- /// field is 32-bit on Darwin and OpenBSD, and 64-bit on FreeBSD.
- @_alwaysEmitIntoClient
- public var generationNumber: UInt64 {
- get { UInt64(rawValue.st_gen) }
- set { rawValue.st_gen = numericCast(newValue) }
- }
- #endif
- }
- // MARK: - Equatable and Hashable
- @available(System 1.7.0, *)
- extension Stat: Equatable {
- /// Compares the meaningful file-metadata fields of two `Stat` values.
- ///
- /// Alignment padding and platform reserved/"spare" fields are not compared.
- public static func == (lhs: Self, rhs: Self) -> Bool {
- guard lhs.rawValue.st_dev == rhs.rawValue.st_dev,
- lhs.rawValue.st_ino == rhs.rawValue.st_ino,
- lhs.rawValue.st_mode == rhs.rawValue.st_mode,
- lhs.rawValue.st_nlink == rhs.rawValue.st_nlink,
- lhs.rawValue.st_uid == rhs.rawValue.st_uid,
- lhs.rawValue.st_gid == rhs.rawValue.st_gid,
- lhs.rawValue.st_rdev == rhs.rawValue.st_rdev,
- lhs.rawValue.st_size == rhs.rawValue.st_size,
- lhs.rawValue.st_blksize == rhs.rawValue.st_blksize,
- lhs.rawValue.st_blocks == rhs.rawValue.st_blocks,
- lhs.st_atim.tv_sec == rhs.st_atim.tv_sec,
- lhs.st_atim.tv_nsec == rhs.st_atim.tv_nsec,
- lhs.st_mtim.tv_sec == rhs.st_mtim.tv_sec,
- lhs.st_mtim.tv_nsec == rhs.st_mtim.tv_nsec,
- lhs.st_ctim.tv_sec == rhs.st_ctim.tv_sec,
- lhs.st_ctim.tv_nsec == rhs.st_ctim.tv_nsec else {
- return false
- }
- #if SYSTEM_PACKAGE_DARWIN || os(FreeBSD)
- guard lhs.st_birthtim.tv_sec == rhs.st_birthtim.tv_sec,
- lhs.st_birthtim.tv_nsec == rhs.st_birthtim.tv_nsec else {
- return false
- }
- #endif
- #if SYSTEM_PACKAGE_DARWIN || os(FreeBSD) || os(OpenBSD)
- guard lhs.rawValue.st_flags == rhs.rawValue.st_flags,
- lhs.rawValue.st_gen == rhs.rawValue.st_gen else {
- return false
- }
- #endif
- return true
- }
- }
- @available(System 1.7.0, *)
- extension Stat: Hashable {
- /// Hashes the meaningful file-metadata fields of a `Stat` struct.
- ///
- /// These are the same fields compared by `==`, fed in the same order.
- /// Alignment padding and platform reserved/"spare" fields are not hashed.
- public func hash(into hasher: inout Hasher) {
- hasher.combine(rawValue.st_dev)
- hasher.combine(rawValue.st_ino)
- hasher.combine(rawValue.st_mode)
- hasher.combine(rawValue.st_nlink)
- hasher.combine(rawValue.st_uid)
- hasher.combine(rawValue.st_gid)
- hasher.combine(rawValue.st_rdev)
- hasher.combine(rawValue.st_size)
- hasher.combine(rawValue.st_blksize)
- hasher.combine(rawValue.st_blocks)
- hasher.combine(st_atim.tv_sec)
- hasher.combine(st_atim.tv_nsec)
- hasher.combine(st_mtim.tv_sec)
- hasher.combine(st_mtim.tv_nsec)
- hasher.combine(st_ctim.tv_sec)
- hasher.combine(st_ctim.tv_nsec)
- #if SYSTEM_PACKAGE_DARWIN || os(FreeBSD)
- hasher.combine(st_birthtim.tv_sec)
- hasher.combine(st_birthtim.tv_nsec)
- #endif
- #if SYSTEM_PACKAGE_DARWIN || os(FreeBSD) || os(OpenBSD)
- hasher.combine(rawValue.st_flags)
- hasher.combine(rawValue.st_gen)
- #endif
- }
- }
- // MARK: - CustomStringConvertible and CustomDebugStringConvertible
- // MARK: - FileDescriptor Extensions
- @available(System 1.7.0, *)
- extension FileDescriptor {
- /// Creates a `Stat` struct for the file referenced by this `FileDescriptor`.
- ///
- /// The corresponding C function is `fstat()`.
- @_alwaysEmitIntoClient
- public func stat(
- retryOnInterrupt: Bool = true
- ) throws(Errno) -> Stat {
- try Stat(self, retryOnInterrupt: retryOnInterrupt)
- }
- }
- // MARK: - FilePath Extensions
- @available(System 1.7.0, *)
- extension FilePath {
- /// Creates a `Stat` struct for the file referenced by this `FilePath`.
- ///
- /// `followTargetSymlink` determines the behavior if `path` ends with a symbolic link.
- /// By default, `followTargetSymlink` is `true` and this initializer behaves like `stat()`.
- /// If `followTargetSymlink` is set to `false`, this initializer behaves like `lstat()` and
- /// returns information about the symlink itself.
- ///
- /// The corresponding C function is `stat()` or `lstat()` as described above.
- @_alwaysEmitIntoClient
- public func stat(
- followTargetSymlink: Bool = true,
- retryOnInterrupt: Bool = true
- ) throws(Errno) -> Stat {
- try Stat(self, followTargetSymlink: followTargetSymlink, retryOnInterrupt: retryOnInterrupt)
- }
- /// Creates a `Stat` struct for the file referenced by this `FilePath` using the given `Flags`.
- ///
- /// If `path` is relative, it is resolved against the current working directory.
- ///
- /// The corresponding C function is `fstatat()`.
- @_alwaysEmitIntoClient
- public func stat(
- flags: Stat.Flags,
- retryOnInterrupt: Bool = true
- ) throws(Errno) -> Stat {
- try Stat(self, flags: flags, retryOnInterrupt: retryOnInterrupt)
- }
- /// Creates a `Stat` struct for the file referenced by this `FilePath` using the given `Flags`,
- /// including a `FileDescriptor` to resolve a relative path.
- ///
- /// If `path` is absolute (starts with a forward slash), then `fd` is ignored.
- /// If `path` is relative, it is resolved against the directory given by `fd`.
- ///
- /// The corresponding C function is `fstatat()`.
- @_alwaysEmitIntoClient
- public func stat(
- relativeTo fd: FileDescriptor,
- flags: Stat.Flags,
- retryOnInterrupt: Bool = true
- ) throws(Errno) -> Stat {
- try Stat(self, relativeTo: fd, flags: flags, retryOnInterrupt: retryOnInterrupt)
- }
- }
- #endif // !os(Windows)
|