diff --git a/Package.swift b/Package.swift index e1c2fa6..bc4e4cb 100644 --- a/Package.swift +++ b/Package.swift @@ -22,9 +22,11 @@ let package = Package( .package(url: "https://github.com/tuist/Noora", from: "0.55.1") ], targets: [ + .systemLibrary(name: "CInotify"), .target( name: "Inotify", dependencies: [ + "CInotify", .product(name: "Logging", package: "swift-log"), ] ), diff --git a/Sources/CInotify/cinotify.h b/Sources/CInotify/cinotify.h new file mode 100644 index 0000000..0c60017 --- /dev/null +++ b/Sources/CInotify/cinotify.h @@ -0,0 +1,24 @@ +#ifndef CINOTIFY_H +#define CINOTIFY_H + +#include +#include +#include + +static inline int cinotify_deinit(int fd) { + return close(fd); +} + +static inline int cinotify_get_errno(void) { + return errno; +} + +static inline char* get_error_message() { + int error_number = errno; + errno = 0; + char* error_message = strerror(error_number); + if (errno > 0) return NULL; + return error_message; +} + +#endif diff --git a/Sources/CInotify/module.modulemap b/Sources/CInotify/module.modulemap new file mode 100644 index 0000000..65e44c8 --- /dev/null +++ b/Sources/CInotify/module.modulemap @@ -0,0 +1,4 @@ +module CInotify [system] { + header "cinotify.h" + export * +} diff --git a/Sources/Inotify/Inotify.swift b/Sources/Inotify/Inotify.swift index 2451248..298c899 100644 --- a/Sources/Inotify/Inotify.swift +++ b/Sources/Inotify/Inotify.swift @@ -1,2 +1,16 @@ -actor Inotify { +import CInotify + +public actor Inotify { + private let fd: Int32 + + public init() throws { + self.fd = inotify_init1(Int32(IN_NONBLOCK | IN_CLOEXEC)) + guard self.fd >= 0 else { + throw InotifyError.initFailed(errno: cinotify_get_errno()) + } + } + + deinit { + cinotify_deinit(self.fd) + } } diff --git a/Sources/Inotify/InotifyError.swift b/Sources/Inotify/InotifyError.swift new file mode 100644 index 0000000..3859856 --- /dev/null +++ b/Sources/Inotify/InotifyError.swift @@ -0,0 +1,19 @@ +import CInotify + +public enum InotifyError: Error, Sendable, CustomStringConvertible { + case initFailed(errno: Int32) + + public var description: String { + switch self { + case .initFailed(let code): + "inotify_init1 failed: \(readableErrno(code))" + } + } + + private func readableErrno(_ code: Int32) -> String { + if let cStr = get_error_message() { + return String(cString: cStr) + " (errno \(code))" + } + return "errno \(code)" + } +} diff --git a/Tests/InotifyIntegrationTests/InitialisationTests.swift b/Tests/InotifyIntegrationTests/InitialisationTests.swift index faef273..50468fd 100644 --- a/Tests/InotifyIntegrationTests/InitialisationTests.swift +++ b/Tests/InotifyIntegrationTests/InitialisationTests.swift @@ -4,6 +4,6 @@ import Testing @Suite("Initialisation") struct InitTests { @Test func createsCleanly() async throws { - let _ = Inotify() + let _ = try Inotify() } }