Skip to content

Commit 28e4f42

Browse files
POSIX: don't force-unwrap result of fdopendir(3)
Motivation: It's possible for fdopendir(3) to return 0 if the file descriptor's backing filesystem is force-unmounted. This should return an error, but instead crashes the library. Result: If fdopendir fails, FileDescriptor.opendir will return the error contained in errno (set by the stat(2) call in libc fdopendir).
1 parent 3bf9c1b commit 28e4f42

File tree

3 files changed

+25
-3
lines changed

3 files changed

+25
-3
lines changed

Sources/NIOFileSystem/Internal/System Calls/Errno.swift

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,3 +146,25 @@ public func valueOrErrno<R>(
146146
}
147147
}
148148
}
149+
150+
151+
/// As `valueOrErrno` but returns `Errno` if result is nil
152+
@_spi(Testing)
153+
public func unwrapValueOrErrno<R>(
154+
retryOnInterrupt: Bool = true,
155+
_ fn: () -> R?
156+
) -> Result<R, Errno> {
157+
while true {
158+
Errno.clear()
159+
if let result = fn() {
160+
return .success(result)
161+
} else {
162+
let errno = Errno._current
163+
if errno == .interrupted, retryOnInterrupt {
164+
continue
165+
} else {
166+
return .failure(errno)
167+
}
168+
}
169+
}
170+
}

Sources/NIOFileSystem/Internal/System Calls/FileDescriptor+Syscalls.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ extension FileDescriptor {
191191
/// caller should not modify the descriptor or close the descriptor via `close()`. Once
192192
/// directory iteration has been completed then `Libc.closdir(_:)` must be called.
193193
internal func opendir() -> Result<CInterop.DirPointer, Errno> {
194-
valueOrErrno(retryOnInterrupt: false) {
194+
unwrapValueOrErrno(retryOnInterrupt: false) {
195195
libc_fdopendir(self.rawValue)
196196
}
197197
}

Sources/NIOFileSystem/Internal/System Calls/Syscalls.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -368,8 +368,8 @@ internal func system_futimens(
368368
/// fdopendir(3): Opens a directory stream for the file descriptor
369369
internal func libc_fdopendir(
370370
_ fd: FileDescriptor.RawValue
371-
) -> CInterop.DirPointer {
372-
fdopendir(fd)!
371+
) -> CInterop.DirPointer? {
372+
fdopendir(fd)
373373
}
374374

375375
/// readdir(3): Returns a pointer to the next directory entry

0 commit comments

Comments
 (0)