Skip to content

[DRAFT][SKETCH] Ideas for stat.h interface #56

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@
swift-system.xcodeproj
xcuserdata/
.*.sw?
.docc-build
.docc-build
234 changes: 234 additions & 0 deletions Sources/System/FileStatus/FileFlags.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
/*
This source file is part of the Swift System open source project

Copyright (c) 2021 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(macOS) || os(iOS) || os(watchOS) || os(tvOS)

// FIXME: Document
@frozen
// @available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *)
public struct FileFlags: OptionSet, Hashable, Codable {
/// The raw C file flags.
@_alwaysEmitIntoClient
public let rawValue: CInterop.FileFlags

/// Create a strongly-typed file flags from a raw C value.
@_alwaysEmitIntoClient
public init(rawValue: CInterop.FileFlags) { self.rawValue = rawValue }

@_alwaysEmitIntoClient
private init(_ raw: CInterop.FileFlags) { self.init(rawValue: raw) }

/// Do not dump the file. Modifiable by file owner or super-user.
///
/// The corresponding C constant is `UF_NODUMP`
@_alwaysEmitIntoClient
public static var noDump: FileFlags { FileFlags(_UF_NODUMP) }

@_alwaysEmitIntoClient
@available(*, unavailable, renamed: "noDump")
public static var UF_NODUMP: FileFlags { noDump }

/// The file may not be changed. Modifiable by file owner or super-user.
///
/// The corresponding C constant is `UF_IMMUTABLE`
@_alwaysEmitIntoClient
public static var immutable: FileFlags { FileFlags(_UF_IMMUTABLE) }

@_alwaysEmitIntoClient
@available(*, unavailable, renamed: "immutable")
public static var UF_IMMUTABLE: FileFlags { immutable }

/// The file may only be appended to. Modifiable by file owner or super-user.
///
/// The corresponding C constant is `UF_APPEND`
@_alwaysEmitIntoClient
public static var appendOnly: FileFlags { FileFlags(_UF_APPEND) }

@_alwaysEmitIntoClient
@available(*, unavailable, renamed: "appendOnly")
public static var UF_APPEND: FileFlags { appendOnly }

/// The directory is opaque when viewed through a union stack. Modifiable by file owner or super-user.
///
/// The corresponding C constant is `UF_OPAQUE`
@_alwaysEmitIntoClient
public static var opaque: FileFlags { FileFlags(_UF_OPAQUE) }

@_alwaysEmitIntoClient
@available(*, unavailable, renamed: "opaque")
public static var UF_OPAQUE: FileFlags { opaque }

// #if os(FreeBSD)
// /// The file may not be removed or renamed. Modifiable by file owner or super-user.
// ///
// /// The corresponding C constant is `UF_NOUNLINK`
// @_alwaysEmitIntoClient
// public static var noUnlink: FileFlags { FileFlags(_UF_NOUNLINK) }
//
// @_alwaysEmitIntoClient
// @available(*, unavailable, renamed: "noUnlink")
// public static var UF_NOUNLINK: FileFlags { noUnlink }
// #endif

/// The file is compressed (some file-systems). Modifiable by file owner or super-user.
///
/// The corresponding C constant is `UF_COMPRESSED`
@_alwaysEmitIntoClient
public static var compressed: FileFlags { FileFlags(_UF_COMPRESSED) }

@_alwaysEmitIntoClient
@available(*, unavailable, renamed: "compressed")
public static var UF_COMPRESSED: FileFlags { compressed }

/// No notifications will be issued for deletes or renames. Modifiable by file owner or super-user.
///
/// The corresponding C constant is `UF_TRACKED`
@_alwaysEmitIntoClient
public static var tracked: FileFlags { FileFlags(_UF_TRACKED) }

@_alwaysEmitIntoClient
@available(*, unavailable, renamed: "tracked")
public static var UF_TRACKED: FileFlags { tracked }

/// The file requires entitlement required for reading and writing. Modifiable by file owner or super-user.
///
/// The corresponding C constant is `UF_DATAVAULT`
@_alwaysEmitIntoClient
public static var dataVault: FileFlags { FileFlags(_UF_DATAVAULT) }

@_alwaysEmitIntoClient
@available(*, unavailable, renamed: "dataVault")
public static var UF_DATAVAULT: FileFlags { dataVault }

/// The file or directory is not intended to be displayed to the user. Modifiable by file owner or super-user.
///
/// The corresponding C constant is `UF_HIDDEN`
@_alwaysEmitIntoClient
public static var hidden: FileFlags { FileFlags(_UF_HIDDEN) }

@_alwaysEmitIntoClient
@available(*, unavailable, renamed: "hidden")
public static var UF_HIDDEN: FileFlags { hidden }

/// The file has been archived. Only modifiable by the super-user.
///
/// The corresponding C constant is `SF_ARCHIVED`
@_alwaysEmitIntoClient
public static var superUserArchived: FileFlags { FileFlags(_SF_ARCHIVED) }

@_alwaysEmitIntoClient
@available(*, unavailable, renamed: "superUserArchived")
public static var SF_ARCHIVED: FileFlags { superUserArchived }

/// The file may not be changed. Only modifiable by the super-user.
///
/// The corresponding C constant is `SF_IMMUTABLE`
@_alwaysEmitIntoClient
public static var superUserImmutable: FileFlags { FileFlags(_SF_IMMUTABLE) }

@_alwaysEmitIntoClient
@available(*, unavailable, renamed: "superUserImmutable")
public static var SF_IMMUTABLE: FileFlags { superUserImmutable }

/// The file may only be appended to. Only modifiable by the super-user.
///
/// The corresponding C constant is `SF_APPEND`
@_alwaysEmitIntoClient
public static var superUserAppend: FileFlags { FileFlags(_SF_APPEND) }

@_alwaysEmitIntoClient
@available(*, unavailable, renamed: "superUserAppend")
public static var SF_APPEND: FileFlags { superUserAppend }

/// The file requires entitlement required for reading and writing. Only modifiable by the super-user.
///
/// The corresponding C constant is `SF_RESTRICTED`
@_alwaysEmitIntoClient
public static var superUserRestricted: FileFlags { FileFlags(_SF_RESTRICTED) }

@_alwaysEmitIntoClient
@available(*, unavailable, renamed: "superUserRestricted")
public static var SF_RESTRICTED: FileFlags { superUserRestricted }

/// The file may not be removed, renamed or mounted on. Only modifiable by the super-user.
///
/// The corresponding C constant is `SF_NOUNLINK`
@_alwaysEmitIntoClient
public static var superUserNoUnlink: FileFlags { FileFlags(_SF_NOUNLINK) }

@_alwaysEmitIntoClient
@available(*, unavailable, renamed: "superUserNoUnlink")
public static var SF_NOUNLINK: FileFlags { superUserNoUnlink }

// #if os(FreeBSD)
// /// The file is a snapshot file. Only modifiable by the super-user.
// ///
// /// The corresponding C constant is `SF_SNAPSHOT`
// @_alwaysEmitIntoClient
// public static var superUserSnapshot: FileFlags { FileFlags(_SF_SNAPSHOT) }
//
// @_alwaysEmitIntoClient
// @available(*, unavailable, renamed: "superUserSnapshot")
// public static var SF_SNAPSHOT: FileFlags { superUserSnapshot }
// #endif

/// The file is a firmlink. Only modifiable by the super-user.
///
/// The corresponding C constant is `SF_FIRMLINK`
@_alwaysEmitIntoClient
public static var superUserFirmlink: FileFlags { FileFlags(_SF_FIRMLINK) }

@_alwaysEmitIntoClient
@available(*, unavailable, renamed: "superUserFirmlink")
public static var SF_FIRMLINK: FileFlags { superUserFirmlink }

/// The file is a dataless placeholder. The system will attempt to materialize it when accessed according to the dataless file materialization policy of the accessing thread or process. Cannot be modified in user-space.
///
/// The corresponding C constant is `SF_DATALESS`
@_alwaysEmitIntoClient
public static var kernelDataless: FileFlags { FileFlags(_SF_DATALESS) }

@_alwaysEmitIntoClient
@available(*, unavailable, renamed: "kernelDataless")
public static var SF_DATALESS: FileFlags { kernelDataless }
}

// @available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *)
extension FileFlags
: CustomStringConvertible, CustomDebugStringConvertible
{
/// A textual representation of the file permissions.
@inline(never)
public var description: String {
let descriptions: [(Element, StaticString)] = [
(.noDump, ".noDump"),
(.immutable, ".immutable"),
(.appendOnly, ".appendOnly"),
(.opaque, ".opaque"),
(.compressed, ".compressed"),
(.tracked, ".tracked"),
(.dataVault, ".dataVault"),
(.hidden, ".hidden"),
(.superUserArchived, ".superUserArchived"),
(.superUserImmutable, ".superUserImmutable"),
(.superUserAppend, ".superUserAppend"),
(.superUserRestricted, ".superUserRestricted"),
(.superUserNoUnlink, ".superUserNoUnlink"),
(.superUserFirmlink, ".superUserFirmlink"),
(.kernelDataless, ".kernelDataless"),
]

return _buildDescription(descriptions)
}

/// A textual representation of the file permissions, suitable for debugging.
public var debugDescription: String { self.description }
}

#endif
47 changes: 47 additions & 0 deletions Sources/System/FileStatus/FileMode.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
This source file is part of the Swift System open source project

Copyright (c) 2021 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(macOS) || os(iOS) || os(watchOS) || os(tvOS)

// FIXME: should the subtypes of Mode mask their rawValues to only allow their bits to be changed?

/// The superset of access permissions and type for a file.
///
/// The following example creates an instance of the `FileMode` structure
/// from a raw octal literal and reads the file type from it:
///
/// let mode = FileMode(rawValue: 0o140000)
/// mode.type == .socket // true
@frozen
// @available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *)
public struct FileMode: RawRepresentable {
/// The raw C file mode.
@_alwaysEmitIntoClient
public var rawValue: CInterop.Mode

/// Create a strongly-typed file mode from a raw C value.
@_alwaysEmitIntoClient
public init(rawValue: CInterop.Mode) { self.rawValue = rawValue }

/// Subset of mode for accessing and modifying file permissions.
@_alwaysEmitIntoClient
public var permissions: FilePermissions {
get { FilePermissions(rawValue: rawValue & _MODE_PERMISSIONS) }
set { rawValue = (rawValue & ~_MODE_PERMISSIONS) | (newValue.rawValue & _MODE_PERMISSIONS ) }
}

/// Subset of mode for accessing and modifying file type.
@_alwaysEmitIntoClient
public var type: FileType {
get { FileType(rawValue: rawValue & _MODE_TYPE) }
set { rawValue = (rawValue & ~_MODE_TYPE) | (newValue.rawValue & _MODE_TYPE ) }
}
}

#endif
91 changes: 91 additions & 0 deletions Sources/System/FileStatus/FileStatus.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
This source file is part of the Swift System open source project

Copyright (c) 2021 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(macOS) || os(iOS) || os(watchOS) || os(tvOS)
import Darwin

// FIXME: Document
@frozen
// @available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *)
public struct FileStatus: RawRepresentable {
/// The raw C file status.
@_alwaysEmitIntoClient
public let rawValue: CInterop.Stat

/// Create a strongly-typed file status from a raw C value.
@_alwaysEmitIntoClient
public init(rawValue: CInterop.Stat) { self.rawValue = rawValue }

// FIXME: replace with swift type DeviceID that splits out major/minor
/// ID of device containing file.
@_alwaysEmitIntoClient
public var deviceID: CInterop.DeviceID { rawValue.st_dev }

/// Mode of file.
@_alwaysEmitIntoClient
public var mode: FileMode { FileMode(rawValue: rawValue.st_mode) }

/// Number of hard links.
@_alwaysEmitIntoClient
public var hardLinkCount: CInterop.NumberOfLinks { rawValue.st_nlink }

/// File serial number.
@_alwaysEmitIntoClient
public var inodeNumber: CInterop.INodeNumber { rawValue.st_ino }

/// User ID of the file.
@_alwaysEmitIntoClient
public var userID: CInterop.UserID { rawValue.st_uid }

/// Group ID of the file.
@_alwaysEmitIntoClient
public var groupID: CInterop.GroupID { rawValue.st_gid }

/// Device ID.
@_alwaysEmitIntoClient
public var rDeviceID: CInterop.DeviceID { rawValue.st_rdev }

/// Time of last access.
@_alwaysEmitIntoClient
public var accessTime: TimeSpecification { TimeSpecification(rawValue: rawValue.st_atimespec) }

/// Time of last data modification.
@_alwaysEmitIntoClient
public var modifyTime: TimeSpecification { TimeSpecification(rawValue: rawValue.st_mtimespec) }

/// Time of last status change.
@_alwaysEmitIntoClient
public var statusChangeTime: TimeSpecification { TimeSpecification(rawValue: rawValue.st_ctimespec) }

/// Time of file creation.
@_alwaysEmitIntoClient
public var creationTime: TimeSpecification { TimeSpecification(rawValue: rawValue.st_birthtimespec) }

/// File size, in bytes.
@_alwaysEmitIntoClient
public var fileSize: CInterop.Offset { rawValue.st_size }

/// Blocks allocated for file.
@_alwaysEmitIntoClient
public var blockCount: CInterop.BlockCount { rawValue.st_blocks }

/// Optimal block size for I/O.
@_alwaysEmitIntoClient
public var blockSize: CInterop.BlockSize { rawValue.st_blksize }

/// User defined flags for file.
@_alwaysEmitIntoClient
public var fileFlags: FileFlags { FileFlags(rawValue: rawValue.st_flags) }

/// File generation number.
@_alwaysEmitIntoClient
public var generationID: CInterop.GenerationID { rawValue.st_gen }
}

#endif
Loading