Skip to content

Commit 2f5b12b

Browse files
committed
Updates for proposal v3
1 parent 905f9f8 commit 2f5b12b

File tree

7 files changed

+111
-68
lines changed

7 files changed

+111
-68
lines changed

Sources/System/FileSystem/FileFlags.swift

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,12 @@
2121
// | systemImmutable | SF_IMMUTABLE | SF_IMMUTABLE | SF_IMMUTABLE |
2222
// | systemAppend | SF_APPEND | SF_APPEND | SF_APPEND |
2323
// | opaque | UF_OPAQUE | UF_OPAQUE | N/A |
24-
// | compressed | UF_COMPRESSED | UF_COMPRESSED | N/A |
25-
// | tracked | UF_TRACKED | UF_TRACKED | N/A |
2624
// | hidden | UF_HIDDEN | UF_HIDDEN | N/A |
27-
// | restricted | SF_RESTRICTED | SF_RESTRICTED | N/A |
2825
// | systemNoUnlink | SF_NOUNLINK | SF_NOUNLINK | N/A |
26+
// | compressed | UF_COMPRESSED | N/A | N/A |
27+
// | tracked | UF_TRACKED | N/A | N/A |
2928
// | dataVault | UF_DATAVAULT | N/A | N/A |
29+
// | restricted | SF_RESTRICTED | N/A | N/A |
3030
// | firmlink | SF_FIRMLINK | N/A | N/A |
3131
// | dataless | SF_DATALESS | N/A | N/A |
3232
// | userNoUnlink | N/A | UF_NOUNLINK | N/A |
@@ -114,34 +114,13 @@ public struct FileFlags: OptionSet, Sendable, Hashable, Codable {
114114
@_alwaysEmitIntoClient
115115
public static var opaque: FileFlags { FileFlags(rawValue: _UF_OPAQUE) }
116116

117-
/// File is compressed at the file system level.
118-
///
119-
/// The corresponding C constant is `UF_COMPRESSED`.
120-
/// - Note: This flag is read-only. Attempting to change it will result in undefined behavior.
121-
@_alwaysEmitIntoClient
122-
public static var compressed: FileFlags { FileFlags(rawValue: _UF_COMPRESSED) }
123-
124-
/// File is tracked for the purpose of document IDs.
125-
///
126-
/// The corresponding C constant is `UF_TRACKED`.
127-
/// - Note: This flag may be changed by the file owner or superuser.
128-
@_alwaysEmitIntoClient
129-
public static var tracked: FileFlags { FileFlags(rawValue: _UF_TRACKED) }
130-
131117
/// File should not be displayed in a GUI.
132118
///
133119
/// The corresponding C constant is `UF_HIDDEN`.
134120
/// - Note: This flag may be changed by the file owner or superuser.
135121
@_alwaysEmitIntoClient
136122
public static var hidden: FileFlags { FileFlags(rawValue: _UF_HIDDEN) }
137123

138-
/// File requires an entitlement for writing.
139-
///
140-
/// The corresponding C constant is `SF_RESTRICTED`.
141-
/// - Note: This flag may only be changed by the superuser.
142-
@_alwaysEmitIntoClient
143-
public static var restricted: FileFlags { FileFlags(rawValue: _SF_RESTRICTED) }
144-
145124
/// File may not be removed or renamed.
146125
///
147126
/// The corresponding C constant is `SF_NOUNLINK`.
@@ -153,13 +132,34 @@ public struct FileFlags: OptionSet, Sendable, Hashable, Codable {
153132
// MARK: Flags Available on Darwin only
154133

155134
#if SYSTEM_PACKAGE_DARWIN
135+
/// File is compressed at the file system level.
136+
///
137+
/// The corresponding C constant is `UF_COMPRESSED`.
138+
/// - Note: This flag is read-only. Attempting to change it will result in undefined behavior.
139+
@_alwaysEmitIntoClient
140+
public static var compressed: FileFlags { FileFlags(rawValue: _UF_COMPRESSED) }
141+
142+
/// File is tracked for the purpose of document IDs.
143+
///
144+
/// The corresponding C constant is `UF_TRACKED`.
145+
/// - Note: This flag may be changed by the file owner or superuser.
146+
@_alwaysEmitIntoClient
147+
public static var tracked: FileFlags { FileFlags(rawValue: _UF_TRACKED) }
148+
156149
/// File requires an entitlement for reading and writing.
157150
///
158151
/// The corresponding C constant is `UF_DATAVAULT`.
159152
/// - Note: This flag may be changed by the file owner or superuser.
160153
@_alwaysEmitIntoClient
161154
public static var dataVault: FileFlags { FileFlags(rawValue: _UF_DATAVAULT) }
162155

156+
/// File requires an entitlement for writing.
157+
///
158+
/// The corresponding C constant is `SF_RESTRICTED`.
159+
/// - Note: This flag may only be changed by the superuser.
160+
@_alwaysEmitIntoClient
161+
public static var restricted: FileFlags { FileFlags(rawValue: _SF_RESTRICTED) }
162+
163163
/// File is a firmlink.
164164
///
165165
/// Firmlinks are used by macOS to create transparent links between

Sources/System/FileSystem/FileMode.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public struct FileMode: RawRepresentable, Sendable, Hashable, Codable {
4444

4545
/// The file's permissions, from the mode's permission bits.
4646
///
47-
/// Setting this property will mask the `newValue` with the permissions bit mask `0o7777`.
47+
/// Setting this property will mask the `newValue` with the permissions bit mask `ALLPERMS`.
4848
@_alwaysEmitIntoClient
4949
public var permissions: FilePermissions {
5050
get { FilePermissions(rawValue: rawValue & _MODE_PERMISSIONS_MASK) }

Sources/System/FileSystem/FileType.swift

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
// | characterSpecial | S_IFCHR |
1919
// | blockSpecial | S_IFBLK |
2020
// | regular | S_IFREG |
21-
// | pipe | S_IFIFO |
21+
// | fifo | S_IFIFO |
2222
// | symbolicLink | S_IFLNK |
2323
// | socket | S_IFSOCK |
2424
// |------------------|---------------------|
@@ -41,11 +41,17 @@ public struct FileType: RawRepresentable, Sendable, Hashable, Codable {
4141
@_alwaysEmitIntoClient
4242
public var rawValue: CInterop.Mode
4343

44-
/// Creates a strongly-typed file type from the raw C value.
44+
/// Creates a strongly-typed file type from the raw C `mode_t`.
4545
///
46-
/// - Note: `rawValue` should only contain the mode's file-type bits. Otherwise,
47-
/// use `FileMode(rawValue:)` to get a strongly-typed `FileMode`, then
48-
/// call `.type` to get the properly masked `FileType`.
46+
/// - Note: This initializer stores the `rawValue` directly and **does not**
47+
/// mask the value with `S_IFMT`. If the supplied `rawValue` contains bits
48+
/// outside of the `S_IFMT` mask, the resulting `FileType` will not compare
49+
/// equal to constants like `.directory` and `.symbolicLink`, which may
50+
/// be unexpected.
51+
///
52+
/// If you're unsure whether the `mode_t` contains bits outside of `S_IFMT`,
53+
/// you can use `FileMode(rawValue:)` instead to get a strongly-typed
54+
/// `FileMode`, then call `.type` to get the properly masked `FileType`.
4955
@_alwaysEmitIntoClient
5056
public init(rawValue: CInterop.Mode) { self.rawValue = rawValue }
5157

@@ -73,11 +79,11 @@ public struct FileType: RawRepresentable, Sendable, Hashable, Codable {
7379
@_alwaysEmitIntoClient
7480
public static var regular: FileType { FileType(rawValue: _S_IFREG) }
7581

76-
/// FIFO (or pipe)
82+
/// FIFO (or named pipe)
7783
///
7884
/// The corresponding C constant is `S_IFIFO`.
7985
@_alwaysEmitIntoClient
80-
public static var pipe: FileType { FileType(rawValue: _S_IFIFO) }
86+
public static var fifo: FileType { FileType(rawValue: _S_IFIFO) }
8187

8288
/// Symbolic link
8389
///

Sources/System/FileSystem/Identifiers.swift

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,13 @@ public struct UserID: RawRepresentable, Sendable, Hashable, Codable {
1919
@_alwaysEmitIntoClient
2020
public var rawValue: CInterop.UserID
2121

22-
/// Creates a strongly-typed `GroupID` from the raw C value.
22+
/// Creates a strongly-typed `UserID` from the raw C value.
2323
@_alwaysEmitIntoClient
2424
public init(rawValue: CInterop.UserID) { self.rawValue = rawValue }
25+
26+
/// Creates a strongly-typed `UserID` from the raw C value.
27+
@_alwaysEmitIntoClient
28+
public init(_ rawValue: CInterop.UserID) { self.rawValue = rawValue }
2529
}
2630

2731
/// A Swift wrapper of the C `gid_t` type.
@@ -36,6 +40,10 @@ public struct GroupID: RawRepresentable, Sendable, Hashable, Codable {
3640
/// Creates a strongly-typed `GroupID` from the raw C value.
3741
@_alwaysEmitIntoClient
3842
public init(rawValue: CInterop.GroupID) { self.rawValue = rawValue }
43+
44+
/// Creates a strongly-typed `GroupID` from the raw C value.
45+
@_alwaysEmitIntoClient
46+
public init(_ rawValue: CInterop.GroupID) { self.rawValue = rawValue }
3947
}
4048

4149
/// A Swift wrapper of the C `dev_t` type.
@@ -51,26 +59,31 @@ public struct DeviceID: RawRepresentable, Sendable, Hashable, Codable {
5159
@_alwaysEmitIntoClient
5260
public init(rawValue: CInterop.DeviceID) { self.rawValue = rawValue }
5361

54-
55-
/// Creates a `DeviceID` from the given major and minor device numbers.
56-
///
57-
/// The corresponding C function is `makedev()`.
62+
/// Creates a strongly-typed `DeviceID` from the raw C value.
5863
@_alwaysEmitIntoClient
59-
public static func make(major: CUnsignedInt, minor: CUnsignedInt) -> DeviceID {
60-
DeviceID(rawValue: system_makedev(major, minor))
61-
}
64+
public init(_ rawValue: CInterop.DeviceID) { self.rawValue = rawValue }
6265

63-
/// The major device number
64-
///
65-
/// The corresponding C function is `major()`.
66-
@_alwaysEmitIntoClient
67-
public var major: CInt { system_major(rawValue) }
66+
// TODO: API review for ID wrapper functionality
6867

69-
/// The minor device number
70-
///
71-
/// The corresponding C function is `minor()`.
72-
@_alwaysEmitIntoClient
73-
public var minor: CInt { system_minor(rawValue) }
68+
// /// Creates a `DeviceID` from the given major and minor device numbers.
69+
// ///
70+
// /// The corresponding C function is `makedev()`.
71+
// @_alwaysEmitIntoClient
72+
// private static func make(major: CUnsignedInt, minor: CUnsignedInt) -> DeviceID {
73+
// DeviceID(rawValue: system_makedev(major, minor))
74+
// }
75+
//
76+
// /// The major device number
77+
// ///
78+
// /// The corresponding C function is `major()`.
79+
// @_alwaysEmitIntoClient
80+
// private var major: CInt { system_major(rawValue) }
81+
//
82+
// /// The minor device number
83+
// ///
84+
// /// The corresponding C function is `minor()`.
85+
// @_alwaysEmitIntoClient
86+
// private var minor: CInt { system_minor(rawValue) }
7487
}
7588

7689
/// A Swift wrapper of the C `ino_t` type.
@@ -85,5 +98,9 @@ public struct Inode: RawRepresentable, Sendable, Hashable, Codable {
8598
/// Creates a strongly-typed `Inode` from the raw C value.
8699
@_alwaysEmitIntoClient
87100
public init(rawValue: CInterop.Inode) { self.rawValue = rawValue }
101+
102+
/// Creates a strongly-typed `Inode` from the raw C value.
103+
@_alwaysEmitIntoClient
104+
public init(_ rawValue: CInterop.Inode) { self.rawValue = rawValue }
88105
}
89106
#endif // !os(Windows)

Sources/System/FileSystem/Stat.swift

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ public struct Stat: RawRepresentable, Sendable {
122122
}.get()
123123
}
124124

125-
/// Creates a `Stat` struct from an`UnsafePointer<CChar>` path.
125+
/// Creates a `Stat` struct from an `UnsafePointer<CChar>` path.
126126
///
127127
/// `followTargetSymlink` determines the behavior if `path` ends with a symbolic link.
128128
/// By default, `followTargetSymlink` is `true` and this initializer behaves like `stat()`.
@@ -314,6 +314,9 @@ public struct Stat: RawRepresentable, Sendable {
314314
}
315315

316316
/// File type for the given mode
317+
///
318+
/// - Note: This property is equivalent to `mode.type`. Modifying this
319+
/// property will update the underlying `st_mode` accordingly.
317320
@_alwaysEmitIntoClient
318321
public var type: FileType {
319322
get { mode.type }
@@ -325,6 +328,9 @@ public struct Stat: RawRepresentable, Sendable {
325328
}
326329

327330
/// File permissions for the given mode
331+
///
332+
/// - Note: This property is equivalent to `mode.permissions`. Modifying
333+
/// this property will update the underlying `st_mode` accordingly.
328334
@_alwaysEmitIntoClient
329335
public var permissions: FilePermissions {
330336
get { mode.permissions }
@@ -365,7 +371,7 @@ public struct Stat: RawRepresentable, Sendable {
365371
/// Device ID (if special file)
366372
///
367373
/// For character or block special files, the returned `DeviceID` may have
368-
/// meaningful `.major` and `.minor` values. For non-special files, this
374+
/// meaningful major and minor values. For non-special files, this
369375
/// property is usually meaningless and often set to 0.
370376
///
371377
/// The corresponding C property is `st_rdev`.
@@ -377,6 +383,12 @@ public struct Stat: RawRepresentable, Sendable {
377383

378384
/// Total size, in bytes
379385
///
386+
/// The semantics of this property are tied to the underlying C `st_size` field,
387+
/// which can have file system-dependent behavior. For example, this property
388+
/// can return different values for a file's data fork and resource fork, and some
389+
/// file systems report logical size rather than actual disk usage for compressed
390+
/// or cloned files.
391+
///
380392
/// The corresponding C property is `st_size`.
381393
@_alwaysEmitIntoClient
382394
public var size: Int64 {
@@ -395,6 +407,9 @@ public struct Stat: RawRepresentable, Sendable {
395407

396408
/// Number of 512-byte blocks allocated
397409
///
410+
/// The semantics of this property are tied to the underlying C `st_blocks` field,
411+
/// which can have file system-dependent behavior.
412+
///
398413
/// The corresponding C property is `st_blocks`.
399414
@_alwaysEmitIntoClient
400415
public var blocksAllocated: Int64 {
@@ -404,12 +419,19 @@ public struct Stat: RawRepresentable, Sendable {
404419

405420
/// Total size allocated, in bytes
406421
///
422+
/// The semantics of this property are tied to the underlying C `st_blocks` field,
423+
/// which can have file system-dependent behavior.
424+
///
407425
/// - Note: Calculated as `512 * blocksAllocated`.
408426
@_alwaysEmitIntoClient
409427
public var sizeAllocated: Int64 {
410428
512 * blocksAllocated
411429
}
412430

431+
// NOTE: "st_" property names are used for the `timespec` properties so
432+
// we can reserve `accessTime`, `modificationTime`, etc. for potential
433+
// `UTCClock.Instant` properties in the future.
434+
413435
/// Time of last access, given as a C `timespec` since the Epoch.
414436
///
415437
/// The corresponding C property is `st_atim` (or `st_atimespec` on Darwin).
@@ -497,7 +519,7 @@ public struct Stat: RawRepresentable, Sendable {
497519
}
498520
#endif
499521

500-
// TODO: jflat - Change time properties to UTCClock.Instant when possible.
522+
// TODO: Investigate changing time properties to UTCClock.Instant once available.
501523

502524
// /// Time of last access, given as a `UTCClock.Instant`
503525
// ///
@@ -602,8 +624,6 @@ extension Stat: Hashable {
602624

603625
// MARK: - CustomStringConvertible and CustomDebugStringConvertible
604626

605-
// TODO: jflat
606-
607627
// MARK: - FileDescriptor Extensions
608628

609629
// @available(System X.Y.Z, *)
@@ -673,7 +693,7 @@ extension FilePath {
673693
}
674694
}
675695

676-
/// Creates a `Stat` struct for the file referenced by this`FilePath` using the given `Flags`.
696+
/// Creates a `Stat` struct for the file referenced by this `FilePath` using the given `Flags`.
677697
///
678698
/// If `path` is relative, it is resolved against the current working directory.
679699
///
@@ -690,7 +710,7 @@ extension FilePath {
690710
).get()
691711
}
692712

693-
/// Creates a `Stat` struct for the file referenced by this`FilePath` using the given `Flags`,
713+
/// Creates a `Stat` struct for the file referenced by this `FilePath` using the given `Flags`,
694714
/// including a `FileDescriptor` to resolve a relative path.
695715
///
696716
/// If `path` is absolute (starts with a forward slash), then `fd` is ignored.

Sources/System/Internals/Constants.swift

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -732,28 +732,28 @@ internal var _SF_APPEND: CInterop.FileFlags { UInt32(bitPattern: SF_APPEND) }
732732
@_alwaysEmitIntoClient
733733
internal var _UF_OPAQUE: CInterop.FileFlags { UInt32(bitPattern: UF_OPAQUE) }
734734

735-
@_alwaysEmitIntoClient
736-
internal var _UF_COMPRESSED: CInterop.FileFlags { UInt32(bitPattern: UF_COMPRESSED) }
737-
738-
@_alwaysEmitIntoClient
739-
internal var _UF_TRACKED: CInterop.FileFlags { UInt32(bitPattern: UF_TRACKED) }
740-
741735
@_alwaysEmitIntoClient
742736
internal var _UF_HIDDEN: CInterop.FileFlags { UInt32(bitPattern: UF_HIDDEN) }
743737

744-
@_alwaysEmitIntoClient
745-
internal var _SF_RESTRICTED: CInterop.FileFlags { UInt32(bitPattern: SF_RESTRICTED) }
746-
747738
@_alwaysEmitIntoClient
748739
internal var _SF_NOUNLINK: CInterop.FileFlags { UInt32(bitPattern: SF_NOUNLINK) }
749740
#endif
750741

751742
// MARK: Flags Available on Darwin Only
752743

753744
#if SYSTEM_PACKAGE_DARWIN
745+
@_alwaysEmitIntoClient
746+
internal var _UF_COMPRESSED: CInterop.FileFlags { UInt32(bitPattern: UF_COMPRESSED) }
747+
748+
@_alwaysEmitIntoClient
749+
internal var _UF_TRACKED: CInterop.FileFlags { UInt32(bitPattern: UF_TRACKED) }
750+
754751
@_alwaysEmitIntoClient
755752
internal var _UF_DATAVAULT: CInterop.FileFlags { UInt32(bitPattern: UF_DATAVAULT) }
756753

754+
@_alwaysEmitIntoClient
755+
internal var _SF_RESTRICTED: CInterop.FileFlags { UInt32(bitPattern: SF_RESTRICTED) }
756+
757757
@_alwaysEmitIntoClient
758758
internal var _SF_FIRMLINK: CInterop.FileFlags { UInt32(bitPattern: SF_FIRMLINK) }
759759

Tests/SystemTests/FileModeTests.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ private struct FileModeTests {
7474
#expect(invalidMode.type != .characterSpecial)
7575
#expect(invalidMode.type != .blockSpecial)
7676
#expect(invalidMode.type != .regular)
77-
#expect(invalidMode.type != .pipe)
77+
#expect(invalidMode.type != .fifo)
7878
#expect(invalidMode.type != .symbolicLink)
7979
#expect(invalidMode.type != .socket)
8080
#if SYSTEM_PACKAGE_DARWIN || os(FreeBSD)
@@ -87,7 +87,7 @@ private struct FileModeTests {
8787
#expect(invalidMode.type != .characterSpecial)
8888
#expect(invalidMode.type != .blockSpecial)
8989
#expect(invalidMode.type != .regular)
90-
#expect(invalidMode.type != .pipe)
90+
#expect(invalidMode.type != .fifo)
9191
#expect(invalidMode.type != .symbolicLink)
9292
#expect(invalidMode.type != .socket)
9393
#if SYSTEM_PACKAGE_DARWIN || os(FreeBSD)

0 commit comments

Comments
 (0)