FileDescriptor.swift 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635
  1. /*
  2. This source file is part of the Swift System open source project
  3. Copyright (c) 2020 - 2026 Apple Inc. and the Swift System project authors
  4. Licensed under Apache License v2.0 with Runtime Library Exception
  5. See https://swift.org/LICENSE.txt for license information
  6. */
  7. /// An abstract handle to an input or output data resource,
  8. /// such as a file or a socket.
  9. ///
  10. /// You are responsible for managing the lifetime and validity
  11. /// of `FileDescriptor` values,
  12. /// in the same way as you manage a raw C file handle.
  13. @frozen
  14. @available(System 0.0.1, *)
  15. public struct FileDescriptor: RawRepresentable, Hashable, Codable {
  16. /// The raw C file handle.
  17. @_alwaysEmitIntoClient
  18. public let rawValue: CInt
  19. /// Creates a strongly-typed file handle from a raw C file handle.
  20. @_alwaysEmitIntoClient
  21. public init(rawValue: CInt) { self.rawValue = rawValue }
  22. }
  23. // Standard file descriptors.
  24. @available(System 0.0.1, *)
  25. extension FileDescriptor {
  26. /// The standard input file descriptor, with a numeric value of 0.
  27. @_alwaysEmitIntoClient
  28. public static var standardInput: FileDescriptor { .init(rawValue: 0) }
  29. /// The standard output file descriptor, with a numeric value of 1.
  30. @_alwaysEmitIntoClient
  31. public static var standardOutput: FileDescriptor { .init(rawValue: 1) }
  32. /// The standard error file descriptor, with a numeric value of 2.
  33. @_alwaysEmitIntoClient
  34. public static var standardError: FileDescriptor { .init(rawValue: 2) }
  35. }
  36. @available(System 0.0.1, *)
  37. extension FileDescriptor {
  38. /// The desired read and write access for a newly opened file.
  39. @frozen
  40. @available(System 0.0.1, *)
  41. public struct AccessMode: RawRepresentable, Sendable, Hashable, Codable {
  42. /// The raw C access mode.
  43. @_alwaysEmitIntoClient
  44. public var rawValue: CInt
  45. /// Creates a strongly-typed access mode from a raw C access mode.
  46. @_alwaysEmitIntoClient
  47. public init(rawValue: CInt) { self.rawValue = rawValue }
  48. /// Opens the file for reading only.
  49. ///
  50. /// The corresponding C constant is `O_RDONLY`.
  51. @_alwaysEmitIntoClient
  52. public static var readOnly: AccessMode { AccessMode(rawValue: _O_RDONLY) }
  53. @_alwaysEmitIntoClient
  54. @available(*, unavailable, renamed: "readOnly")
  55. public static var O_RDONLY: AccessMode { readOnly }
  56. /// Opens the file for writing only.
  57. ///
  58. /// The corresponding C constant is `O_WRONLY`.
  59. @_alwaysEmitIntoClient
  60. public static var writeOnly: AccessMode { AccessMode(rawValue: _O_WRONLY) }
  61. @_alwaysEmitIntoClient
  62. @available(*, unavailable, renamed: "writeOnly")
  63. public static var O_WRONLY: AccessMode { writeOnly }
  64. /// Opens the file for reading and writing.
  65. ///
  66. /// The corresponding C constant is `O_RDWR`.
  67. @_alwaysEmitIntoClient
  68. public static var readWrite: AccessMode { AccessMode(rawValue: _O_RDWR) }
  69. @_alwaysEmitIntoClient
  70. @available(*, unavailable, renamed: "readWrite")
  71. public static var O_RDWR: AccessMode { readWrite }
  72. }
  73. /// Options that specify behavior for a newly-opened file.
  74. @frozen
  75. @available(System 0.0.1, *)
  76. public struct OpenOptions: OptionSet, Sendable, Hashable, Codable {
  77. /// The raw C options.
  78. @_alwaysEmitIntoClient
  79. public var rawValue: CInt
  80. /// Create a strongly-typed options value from raw C options.
  81. @_alwaysEmitIntoClient
  82. public init(rawValue: CInt) { self.rawValue = rawValue }
  83. #if !os(Windows)
  84. /// Indicates that opening the file doesn't
  85. /// wait for the file or device to become available.
  86. ///
  87. /// If this option is specified,
  88. /// the system doesn't wait for the device or file
  89. /// to be ready or available.
  90. /// If the
  91. /// <doc:FileDescriptor/open(_:_:options:permissions:retryOnInterrupt:)-2266j>
  92. /// call would result in the process being blocked for some reason,
  93. /// that method returns immediately.
  94. /// This flag also has the effect of making all
  95. /// subsequent input and output operations on the open file nonblocking.
  96. ///
  97. /// The corresponding C constant is `O_NONBLOCK`.
  98. @_alwaysEmitIntoClient
  99. public static var nonBlocking: OpenOptions { .init(rawValue: _O_NONBLOCK) }
  100. @_alwaysEmitIntoClient
  101. @available(*, unavailable, renamed: "nonBlocking")
  102. public static var O_NONBLOCK: OpenOptions { nonBlocking }
  103. #endif
  104. /// Indicates that each write operation appends to the file.
  105. ///
  106. /// If this option is specified,
  107. /// each time you write to the file,
  108. /// the new data is written at the end of the file,
  109. /// after all existing file data.
  110. ///
  111. /// The corresponding C constant is `O_APPEND`.
  112. @_alwaysEmitIntoClient
  113. public static var append: OpenOptions { .init(rawValue: _O_APPEND) }
  114. @_alwaysEmitIntoClient
  115. @available(*, unavailable, renamed: "append")
  116. public static var O_APPEND: OpenOptions { append }
  117. /// Indicates that opening the file creates the file if it doesn't exist.
  118. ///
  119. /// The corresponding C constant is `O_CREAT`.
  120. @_alwaysEmitIntoClient
  121. public static var create: OpenOptions { .init(rawValue: _O_CREAT) }
  122. @_alwaysEmitIntoClient
  123. @available(*, unavailable, renamed: "create")
  124. public static var O_CREAT: OpenOptions { create }
  125. /// Indicates that opening the file truncates the file if it exists.
  126. ///
  127. /// If this option is specified and the file exists,
  128. /// the file is truncated to zero bytes
  129. /// before any other operations are performed.
  130. ///
  131. /// The corresponding C constant is `O_TRUNC`.
  132. @_alwaysEmitIntoClient
  133. public static var truncate: OpenOptions { .init(rawValue: _O_TRUNC) }
  134. @_alwaysEmitIntoClient
  135. @available(*, unavailable, renamed: "truncate")
  136. public static var O_TRUNC: OpenOptions { truncate }
  137. /// Indicates that opening the file creates the file,
  138. /// expecting that it doesn't exist.
  139. ///
  140. /// If this option and ``create`` are both specified and the file exists,
  141. /// <doc:FileDescriptor/open(_:_:options:permissions:retryOnInterrupt:)-2266j>
  142. /// returns an error instead of creating the file.
  143. /// You can use this, for example,
  144. /// to implement a simple exclusive-access locking mechanism.
  145. ///
  146. /// If this option and ``create`` are both specified
  147. /// and the last component of the file's path is a symbolic link,
  148. /// <doc:FileDescriptor/open(_:_:options:permissions:retryOnInterrupt:)-2266j>
  149. /// fails even if the symbolic link points to a nonexistent name.
  150. ///
  151. /// The corresponding C constant is `O_EXCL`.
  152. @_alwaysEmitIntoClient
  153. public static var exclusiveCreate: OpenOptions { .init(rawValue: _O_EXCL) }
  154. @_alwaysEmitIntoClient
  155. @available(*, unavailable, renamed: "exclusiveCreate")
  156. public static var O_EXCL: OpenOptions { exclusiveCreate }
  157. #if SYSTEM_PACKAGE_DARWIN || os(FreeBSD)
  158. /// Indicates that opening the file
  159. /// atomically obtains a shared lock on the file.
  160. ///
  161. /// Setting this option or the ``exclusiveLock`` option
  162. /// obtains a lock with `flock(2)` semantics.
  163. /// If you're creating a file using the ``create`` option,
  164. /// the request for the lock always succeeds
  165. /// except on file systems that don't support locking.
  166. ///
  167. /// The corresponding C constant is `O_SHLOCK`.
  168. @_alwaysEmitIntoClient
  169. public static var sharedLock: OpenOptions { .init(rawValue: _O_SHLOCK) }
  170. @_alwaysEmitIntoClient
  171. @available(*, unavailable, renamed: "sharedLock")
  172. public static var O_SHLOCK: OpenOptions { sharedLock }
  173. /// Indicates that opening the file
  174. /// atomically obtains an exclusive lock.
  175. ///
  176. /// Setting this option or the ``sharedLock`` option.
  177. /// obtains a lock with `flock(2)` semantics.
  178. /// If you're creating a file using the ``create`` option,
  179. /// the request for the lock always succeeds
  180. /// except on file systems that don't support locking.
  181. ///
  182. /// The corresponding C constant is `O_EXLOCK`.
  183. @_alwaysEmitIntoClient
  184. public static var exclusiveLock: OpenOptions { .init(rawValue: _O_EXLOCK) }
  185. @_alwaysEmitIntoClient
  186. @available(*, unavailable, renamed: "exclusiveLock")
  187. public static var O_EXLOCK: OpenOptions { exclusiveLock }
  188. #endif
  189. #if !os(Windows)
  190. /// Indicates that opening the file doesn't follow symlinks.
  191. ///
  192. /// If you specify this option
  193. /// and the file path you pass to
  194. /// <doc:FileDescriptor/open(_:_:options:permissions:retryOnInterrupt:)-2266j>
  195. /// is a symbolic link,
  196. /// then that open operation fails.
  197. ///
  198. /// The corresponding C constant is `O_NOFOLLOW`.
  199. @_alwaysEmitIntoClient
  200. public static var noFollow: OpenOptions { .init(rawValue: _O_NOFOLLOW) }
  201. @_alwaysEmitIntoClient
  202. @available(*, unavailable, renamed: "noFollow")
  203. public static var O_NOFOLLOW: OpenOptions { noFollow }
  204. /// Indicates that opening the file only succeeds if the file is a directory.
  205. ///
  206. /// If you specify this option and the file path you pass to
  207. /// <doc:FileDescriptor/open(_:_:options:permissions:retryOnInterrupt:)-2266j>
  208. /// is a not a directory, then that open operation fails.
  209. ///
  210. /// The corresponding C constant is `O_DIRECTORY`.
  211. @_alwaysEmitIntoClient
  212. public static var directory: OpenOptions { .init(rawValue: _O_DIRECTORY) }
  213. @_alwaysEmitIntoClient
  214. @available(*, unavailable, renamed: "directory")
  215. public static var O_DIRECTORY: OpenOptions { directory }
  216. #endif
  217. #if os(FreeBSD)
  218. /// Indicates that each write operation is synchronous.
  219. ///
  220. /// If this option is specified,
  221. /// each time you write to the file,
  222. /// the new data is written immediately and synchronously to the disk.
  223. ///
  224. /// The corresponding C constant is `O_SYNC`.
  225. @_alwaysEmitIntoClient
  226. public static var sync: OpenOptions { .init(rawValue: _O_SYNC) }
  227. @_alwaysEmitIntoClient
  228. @available(*, unavailable, renamed: "sync")
  229. public static var O_SYNC: OpenOptions { sync }
  230. #endif
  231. #if SYSTEM_PACKAGE_DARWIN
  232. /// Indicates that opening the file
  233. /// opens symbolic links instead of following them.
  234. ///
  235. /// If you specify this option
  236. /// and the file path you pass to
  237. /// <doc:FileDescriptor/open(_:_:options:permissions:retryOnInterrupt:)-2266j>
  238. /// is a symbolic link,
  239. /// then the link itself is opened instead of what it links to.
  240. ///
  241. /// The corresponding C constant is `O_SYMLINK`.
  242. @_alwaysEmitIntoClient
  243. public static var symlink: OpenOptions { .init(rawValue: _O_SYMLINK) }
  244. @_alwaysEmitIntoClient
  245. @available(*, unavailable, renamed: "symlink")
  246. public static var O_SYMLINK: OpenOptions { symlink }
  247. /// Indicates that opening the file monitors a file for changes.
  248. ///
  249. /// Specify this option when opening a file for event notifications,
  250. /// such as a file handle returned by the `kqueue(2)` function,
  251. /// rather than for reading or writing.
  252. /// Files opened with this option
  253. /// don't prevent their containing volume from being unmounted.
  254. ///
  255. /// The corresponding C constant is `O_EVTONLY`.
  256. @_alwaysEmitIntoClient
  257. public static var eventOnly: OpenOptions { .init(rawValue: _O_EVTONLY) }
  258. @_alwaysEmitIntoClient
  259. @available(*, unavailable, renamed: "eventOnly")
  260. public static var O_EVTONLY: OpenOptions { eventOnly }
  261. #endif
  262. /// Indicates that executing a program closes the file.
  263. ///
  264. /// Normally, file descriptors remain open
  265. /// across calls to the `exec(2)` family of functions.
  266. /// If you specify this option, the system closes the file
  267. /// descriptor when replacing this process with another process.
  268. ///
  269. /// You can inspect the file descriptor flag state using `F_GETFD`,
  270. /// as described in the `fcntl(2)` man page.
  271. ///
  272. /// The corresponding C constant is `O_CLOEXEC`.
  273. @_alwaysEmitIntoClient
  274. public static var closeOnExec: OpenOptions { .init(rawValue: _O_CLOEXEC) }
  275. @_alwaysEmitIntoClient
  276. @available(*, unavailable, renamed: "closeOnExec")
  277. public static var O_CLOEXEC: OpenOptions { closeOnExec }
  278. #if os(Windows)
  279. @_alwaysEmitIntoClient
  280. @available(*, unavailable, renamed: "closeOnExec")
  281. public static var O_NOINHERIT: OpenOptions { closeOnExec }
  282. #endif
  283. }
  284. /// Options that specify behavior for a newly-created pipe.
  285. @frozen
  286. @available(macOS 27.0, iOS 27.0, watchOS 27.0, tvOS 27.0, visionOS 27.0, *)
  287. public struct PipeOptions: OptionSet, Sendable, Hashable, Codable {
  288. /// The raw C options.
  289. @_alwaysEmitIntoClient
  290. public var rawValue: CInt
  291. /// Create a strongly-typed options value from raw C options.
  292. @_alwaysEmitIntoClient
  293. public init(rawValue: CInt) { self.rawValue = rawValue }
  294. #if !os(Windows)
  295. /// Indicates that all subsequent input and output operations
  296. /// on the pipe's file descriptors will be nonblocking.
  297. ///
  298. /// The corresponding C constant is `O_NONBLOCK`.
  299. @_alwaysEmitIntoClient
  300. public static var nonBlocking: PipeOptions { .init(rawValue: _O_NONBLOCK) }
  301. @_alwaysEmitIntoClient
  302. @available(*, unavailable, renamed: "nonBlocking")
  303. public static var O_NONBLOCK: PipeOptions { nonBlocking }
  304. #endif // !os(Windows)
  305. /// Indicates that executing a program closes the file.
  306. ///
  307. /// Normally, file descriptors remain open
  308. /// across calls to the `exec(2)` family of functions.
  309. /// If you specify this option, the system closes the file
  310. /// descriptor when replacing this process with another process.
  311. ///
  312. /// You can inspect the file descriptor flag state using `F_GETFD`,
  313. /// as described in the `fcntl(2)` man page.
  314. ///
  315. /// The corresponding C constant is `O_CLOEXEC`.
  316. @_alwaysEmitIntoClient
  317. public static var closeOnExec: PipeOptions { .init(rawValue: _O_CLOEXEC) }
  318. @_alwaysEmitIntoClient
  319. @available(*, unavailable, renamed: "closeOnExec")
  320. public static var O_CLOEXEC: PipeOptions { closeOnExec }
  321. #if os(Windows)
  322. @_alwaysEmitIntoClient
  323. @available(*, unavailable, renamed: "closeOnExec")
  324. public static var O_NOINHERIT: PipeOptions { closeOnExec }
  325. #endif
  326. #if !os(Windows) && !os(WASI) && !os(Linux) && !os(Android)
  327. /// Indicates that forking a program closes the file.
  328. ///
  329. /// Normally, file descriptors remain open
  330. /// across calls to the `fork(2)` function.
  331. /// If you specify this option, the system closes the file
  332. /// descriptor when forking this process into another process.
  333. ///
  334. /// You can inspect the file descriptor flag state using `F_GETFD`,
  335. /// as described in the `fcntl(2)` man page.
  336. ///
  337. /// The corresponding C constant is `O_CLOFORK`.
  338. @_alwaysEmitIntoClient
  339. public static var closeOnFork: PipeOptions { .init(rawValue: _O_CLOFORK) }
  340. @_alwaysEmitIntoClient
  341. @available(*, unavailable, renamed: "closeOnFork")
  342. public static var O_CLOFORK: PipeOptions { closeOnFork }
  343. #endif
  344. }
  345. /// Options that specify behavior for a duplicated file descriptor.
  346. @frozen
  347. @available(Windows, unavailable)
  348. @available(macOS 27.0, iOS 27.0, watchOS 27.0, tvOS 27.0, visionOS 27.0, *)
  349. public struct DuplicateOptions: OptionSet, Sendable, Hashable, Codable {
  350. /// The raw C options.
  351. @_alwaysEmitIntoClient
  352. public var rawValue: CInt
  353. /// Create a strongly-typed options value from raw C options.
  354. @_alwaysEmitIntoClient
  355. public init(rawValue: CInt) { self.rawValue = rawValue }
  356. #if !os(Windows)
  357. /// Indicates that executing a program closes the file.
  358. ///
  359. /// Normally, file descriptors remain open
  360. /// across calls to the `exec(2)` family of functions.
  361. /// If you specify this option, the system closes the file
  362. /// descriptor when replacing this process with another process.
  363. ///
  364. /// You can inspect the file descriptor flag state using `F_GETFD`,
  365. /// as described in the `fcntl(2)` man page.
  366. ///
  367. /// The corresponding C constant is `O_CLOEXEC`.
  368. @_alwaysEmitIntoClient
  369. public static var closeOnExec: DuplicateOptions { .init(rawValue: _O_CLOEXEC) }
  370. @_alwaysEmitIntoClient
  371. @available(*, unavailable, renamed: "closeOnExec")
  372. public static var O_CLOEXEC: DuplicateOptions { closeOnExec }
  373. #if !os(WASI) && !os(Linux) && !os(Android)
  374. /// Indicates that forking a program closes the file.
  375. ///
  376. /// Normally, file descriptors remain open
  377. /// across calls to the `fork(2)` function.
  378. /// If you specify this option, the system closes the file
  379. /// descriptor when forking this process into another process.
  380. ///
  381. /// You can inspect the file descriptor flag state using `F_GETFD`,
  382. /// as described in the `fcntl(2)` man page.
  383. ///
  384. /// The corresponding C constant is `O_CLOFORK`.
  385. @_alwaysEmitIntoClient
  386. public static var closeOnFork: DuplicateOptions { .init(rawValue: _O_CLOFORK) }
  387. @_alwaysEmitIntoClient
  388. @available(*, unavailable, renamed: "closeOnFork")
  389. public static var O_CLOFORK: DuplicateOptions { closeOnFork }
  390. #endif
  391. #endif
  392. }
  393. /// Options for specifying what a file descriptor's offset is relative to.
  394. @frozen
  395. @available(System 0.0.1, *)
  396. public struct SeekOrigin: RawRepresentable, Sendable, Hashable, Codable {
  397. /// The raw C value.
  398. @_alwaysEmitIntoClient
  399. public var rawValue: CInt
  400. /// Create a strongly-typed seek origin from a raw C value.
  401. @_alwaysEmitIntoClient
  402. public init(rawValue: CInt) { self.rawValue = rawValue }
  403. /// Indicates that the offset should be set to the specified value.
  404. ///
  405. /// The corresponding C constant is `SEEK_SET`.
  406. @_alwaysEmitIntoClient
  407. public static var start: SeekOrigin { SeekOrigin(rawValue: _SEEK_SET) }
  408. @_alwaysEmitIntoClient
  409. @available(*, unavailable, renamed: "start")
  410. public static var SEEK_SET: SeekOrigin { start }
  411. /// Indicates that the offset should be set
  412. /// to the specified number of bytes after the current location.
  413. ///
  414. /// The corresponding C constant is `SEEK_CUR`.
  415. @_alwaysEmitIntoClient
  416. public static var current: SeekOrigin { SeekOrigin(rawValue: _SEEK_CUR) }
  417. @_alwaysEmitIntoClient
  418. @available(*, unavailable, renamed: "current")
  419. public static var SEEK_CUR: SeekOrigin { current }
  420. /// Indicates that the offset should be set
  421. /// to the size of the file plus the specified number of bytes.
  422. ///
  423. /// The corresponding C constant is `SEEK_END`.
  424. @_alwaysEmitIntoClient
  425. public static var end: SeekOrigin { SeekOrigin(rawValue: _SEEK_END) }
  426. @_alwaysEmitIntoClient
  427. @available(*, unavailable, renamed: "end")
  428. public static var SEEK_END: SeekOrigin { end }
  429. // TODO: These are available on some versions of Linux with appropriate
  430. // macro defines.
  431. #if SYSTEM_PACKAGE_DARWIN || os(FreeBSD)
  432. /// Indicates that the offset should be set
  433. /// to the next hole after the specified number of bytes.
  434. ///
  435. /// For information about what is considered a hole,
  436. /// see the `lseek(2)` man page.
  437. ///
  438. /// The corresponding C constant is `SEEK_HOLE`.
  439. @_alwaysEmitIntoClient
  440. public static var nextHole: SeekOrigin { SeekOrigin(rawValue: _SEEK_HOLE) }
  441. @_alwaysEmitIntoClient
  442. @available(*, unavailable, renamed: "nextHole")
  443. public static var SEEK_HOLE: SeekOrigin { nextHole }
  444. /// Indicates that the offset should be set
  445. /// to the start of the next file region
  446. /// that isn't a hole
  447. /// and is greater than or equal to the supplied offset.
  448. ///
  449. /// The corresponding C constant is `SEEK_DATA`.
  450. @_alwaysEmitIntoClient
  451. public static var nextData: SeekOrigin { SeekOrigin(rawValue: _SEEK_DATA) }
  452. @_alwaysEmitIntoClient
  453. @available(*, unavailable, renamed: "nextData")
  454. public static var SEEK_DATA: SeekOrigin { nextData }
  455. #endif
  456. }
  457. }
  458. @available(System 0.0.1, *)
  459. extension FileDescriptor.AccessMode
  460. : CustomStringConvertible, CustomDebugStringConvertible
  461. {
  462. /// A textual representation of the access mode.
  463. @inline(never)
  464. public var description: String {
  465. switch self {
  466. case .readOnly: return "readOnly"
  467. case .writeOnly: return "writeOnly"
  468. case .readWrite: return "readWrite"
  469. default: return "\(Self.self)(rawValue: \(self.rawValue))"
  470. }
  471. }
  472. /// A textual representation of the access mode, suitable for debugging
  473. public var debugDescription: String { self.description }
  474. }
  475. @available(System 0.0.1, *)
  476. extension FileDescriptor.SeekOrigin
  477. : CustomStringConvertible, CustomDebugStringConvertible
  478. {
  479. /// A textual representation of the seek origin.
  480. @inline(never)
  481. public var description: String {
  482. switch self {
  483. case .start: return "start"
  484. case .current: return "current"
  485. case .end: return "end"
  486. #if SYSTEM_PACKAGE_DARWIN
  487. case .nextHole: return "nextHole"
  488. case .nextData: return "nextData"
  489. #endif
  490. default: return "\(Self.self)(rawValue: \(self.rawValue))"
  491. }
  492. }
  493. /// A textual representation of the seek origin, suitable for debugging.
  494. public var debugDescription: String { self.description }
  495. }
  496. @available(System 0.0.1, *)
  497. extension FileDescriptor.OpenOptions
  498. : CustomStringConvertible, CustomDebugStringConvertible
  499. {
  500. /// A textual representation of the open options.
  501. @inline(never)
  502. public var description: String {
  503. #if SYSTEM_PACKAGE_DARWIN
  504. let descriptions: [(Element, StaticString)] = [
  505. (.nonBlocking, ".nonBlocking"),
  506. (.append, ".append"),
  507. (.create, ".create"),
  508. (.truncate, ".truncate"),
  509. (.exclusiveCreate, ".exclusiveCreate"),
  510. (.sharedLock, ".sharedLock"),
  511. (.exclusiveLock, ".exclusiveLock"),
  512. (.noFollow, ".noFollow"),
  513. (.symlink, ".symlink"),
  514. (.eventOnly, ".eventOnly"),
  515. (.closeOnExec, ".closeOnExec")
  516. ]
  517. #elseif os(Windows)
  518. let descriptions: [(Element, StaticString)] = [
  519. (.append, ".append"),
  520. (.create, ".create"),
  521. (.truncate, ".truncate"),
  522. (.exclusiveCreate, ".exclusiveCreate"),
  523. ]
  524. #elseif os(FreeBSD)
  525. let descriptions: [(Element, StaticString)] = [
  526. (.nonBlocking, ".nonBlocking"),
  527. (.append, ".append"),
  528. (.create, ".create"),
  529. (.truncate, ".truncate"),
  530. (.exclusiveCreate, ".exclusiveCreate"),
  531. (.sharedLock, ".sharedLock"),
  532. (.exclusiveLock, ".exclusiveLock"),
  533. (.sync, ".sync"),
  534. (.noFollow, ".noFollow"),
  535. (.closeOnExec, ".closeOnExec")
  536. ]
  537. #else
  538. let descriptions: [(Element, StaticString)] = [
  539. (.nonBlocking, ".nonBlocking"),
  540. (.append, ".append"),
  541. (.create, ".create"),
  542. (.truncate, ".truncate"),
  543. (.exclusiveCreate, ".exclusiveCreate"),
  544. (.noFollow, ".noFollow"),
  545. (.closeOnExec, ".closeOnExec")
  546. ]
  547. #endif
  548. return _buildDescription(descriptions)
  549. }
  550. /// A textual representation of the open options, suitable for debugging.
  551. public var debugDescription: String { self.description }
  552. }
  553. // The decision on whether to make FileDescriptor Sendable or not
  554. // is currently being discussed in https://github.com/apple/swift-system/pull/112
  555. //@available(*, unavailable, message: "File descriptors are not completely thread-safe.")
  556. //extension FileDescriptor: Sendable {}